]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - pageant.c
Fix Makefile warning about circular empty.h dependency.
[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                 fail_reason = "request truncated before challenge";
410                 goto failure;
411             }
412             p += i;
413             if (msgend < p+16) {
414                 freebn(reqkey.exponent);
415                 freebn(reqkey.modulus);
416                 freebn(challenge);
417                 fail_reason = "request truncated before session id";
418                 goto failure;
419             }
420             memcpy(response_source + 32, p, 16);
421             p += 16;
422             if (msgend < p+4) {
423                 freebn(reqkey.exponent);
424                 freebn(reqkey.modulus);
425                 freebn(challenge);
426                 fail_reason = "request truncated before response type";
427                 goto failure;
428             }
429             if (GET_32BIT(p) != 1) {
430                 freebn(reqkey.exponent);
431                 freebn(reqkey.modulus);
432                 freebn(challenge);
433                 fail_reason = "response type other than 1 not supported";
434                 goto failure;
435             }
436             if (logfn) {
437                 char fingerprint[128];
438                 reqkey.comment = NULL;
439                 rsa_fingerprint(fingerprint, sizeof(fingerprint), &reqkey);
440                 plog(logctx, logfn, "requested key: %s", fingerprint);
441             }
442             if ((key = find234(rsakeys, &reqkey, NULL)) == NULL) {
443                 freebn(reqkey.exponent);
444                 freebn(reqkey.modulus);
445                 freebn(challenge);
446                 fail_reason = "key not found";
447                 goto failure;
448             }
449             response = rsadecrypt(challenge, key);
450             for (i = 0; i < 32; i++)
451                 response_source[i] = bignum_byte(response, 31 - i);
452
453             MD5Init(&md5c);
454             MD5Update(&md5c, response_source, 48);
455             MD5Final(response_md5, &md5c);
456             smemclr(response_source, 48);       /* burn the evidence */
457             freebn(response);          /* and that evidence */
458             freebn(challenge);         /* yes, and that evidence */
459             freebn(reqkey.exponent);   /* and free some memory ... */
460             freebn(reqkey.modulus);    /* ... while we're at it. */
461
462             /*
463              * Packet is the obvious five byte header, plus sixteen
464              * bytes of MD5.
465              */
466             len = 5 + 16;
467             PUT_32BIT(ret, len - 4);
468             ret[4] = SSH1_AGENT_RSA_RESPONSE;
469             memcpy(ret + 5, response_md5, 16);
470
471             plog(logctx, logfn, "reply: SSH1_AGENT_RSA_RESPONSE");
472         }
473         break;
474       case SSH2_AGENTC_SIGN_REQUEST:
475         /*
476          * Reply with either SSH2_AGENT_SIGN_RESPONSE or
477          * SSH_AGENT_FAILURE, depending on whether we have that key
478          * or not.
479          */
480         {
481             struct ssh2_userkey *key;
482             struct blob b;
483             const unsigned char *data;
484             unsigned char *signature;
485             int datalen, siglen, len;
486
487             plog(logctx, logfn, "request: SSH2_AGENTC_SIGN_REQUEST");
488
489             if (msgend < p+4) {
490                 fail_reason = "request truncated before public key";
491                 goto failure;
492             }
493             b.len = toint(GET_32BIT(p));
494             if (b.len < 0 || b.len > msgend - (p+4)) {
495                 fail_reason = "request truncated before public key";
496                 goto failure;
497             }
498             p += 4;
499             b.blob = p;
500             p += b.len;
501             if (msgend < p+4) {
502                 fail_reason = "request truncated before string to sign";
503                 goto failure;
504             }
505             datalen = toint(GET_32BIT(p));
506             p += 4;
507             if (datalen < 0 || datalen > msgend - p) {
508                 fail_reason = "request truncated before string to sign";
509                 goto failure;
510             }
511             data = p;
512             if (logfn) {
513                 char *fingerprint = ssh2_fingerprint_blob(b.blob, b.len);
514                 plog(logctx, logfn, "requested key: %s", fingerprint);
515                 sfree(fingerprint);
516             }
517             key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm);
518             if (!key) {
519                 fail_reason = "key not found";
520                 goto failure;
521             }
522             signature = key->alg->sign(key->data, (const char *)data,
523                                        datalen, &siglen);
524             len = 5 + 4 + siglen;
525             PUT_32BIT(ret, len - 4);
526             ret[4] = SSH2_AGENT_SIGN_RESPONSE;
527             PUT_32BIT(ret + 5, siglen);
528             memcpy(ret + 5 + 4, signature, siglen);
529             sfree(signature);
530
531             plog(logctx, logfn, "reply: SSH2_AGENT_SIGN_RESPONSE");
532         }
533         break;
534       case SSH1_AGENTC_ADD_RSA_IDENTITY:
535         /*
536          * Add to the list and return SSH_AGENT_SUCCESS, or
537          * SSH_AGENT_FAILURE if the key was malformed.
538          */
539         {
540             struct RSAKey *key;
541             char *comment;
542             int n, commentlen;
543
544             plog(logctx, logfn, "request: SSH1_AGENTC_ADD_RSA_IDENTITY");
545
546             key = snew(struct RSAKey);
547             memset(key, 0, sizeof(struct RSAKey));
548
549             n = makekey(p, msgend - p, key, NULL, 1);
550             if (n < 0) {
551                 freersakey(key);
552                 sfree(key);
553                 fail_reason = "request truncated before public key";
554                 goto failure;
555             }
556             p += n;
557
558             n = makeprivate(p, msgend - p, key);
559             if (n < 0) {
560                 freersakey(key);
561                 sfree(key);
562                 fail_reason = "request truncated before private key";
563                 goto failure;
564             }
565             p += n;
566
567             /* SSH-1 names p and q the other way round, i.e. we have
568              * the inverse of p mod q and not of q mod p. We swap the
569              * names, because our internal RSA wants iqmp. */
570
571             n = ssh1_read_bignum(p, msgend - p, &key->iqmp);  /* p^-1 mod q */
572             if (n < 0) {
573                 freersakey(key);
574                 sfree(key);
575                 fail_reason = "request truncated before iqmp";
576                 goto failure;
577             }
578             p += n;
579
580             n = ssh1_read_bignum(p, msgend - p, &key->q);  /* p */
581             if (n < 0) {
582                 freersakey(key);
583                 sfree(key);
584                 fail_reason = "request truncated before p";
585                 goto failure;
586             }
587             p += n;
588
589             n = ssh1_read_bignum(p, msgend - p, &key->p);  /* q */
590             if (n < 0) {
591                 freersakey(key);
592                 sfree(key);
593                 fail_reason = "request truncated before q";
594                 goto failure;
595             }
596             p += n;
597
598             if (msgend < p+4) {
599                 freersakey(key);
600                 sfree(key);
601                 fail_reason = "request truncated before key comment";
602                 goto failure;
603             }
604             commentlen = toint(GET_32BIT(p));
605
606             if (commentlen < 0 || commentlen > msgend - p) {
607                 freersakey(key);
608                 sfree(key);
609                 fail_reason = "request truncated before key comment";
610                 goto failure;
611             }
612
613             comment = snewn(commentlen+1, char);
614             if (comment) {
615                 memcpy(comment, p + 4, commentlen);
616                 comment[commentlen] = '\0';
617                 key->comment = comment;
618             }
619
620             if (logfn) {
621                 char fingerprint[128];
622                 rsa_fingerprint(fingerprint, sizeof(fingerprint), key);
623                 plog(logctx, logfn, "submitted key: %s", fingerprint);
624             }
625
626             if (add234(rsakeys, key) == key) {
627                 keylist_update();
628                 PUT_32BIT(ret, 1);
629                 ret[4] = SSH_AGENT_SUCCESS;
630
631                 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
632             } else {
633                 freersakey(key);
634                 sfree(key);
635
636                 fail_reason = "key already present";
637                 goto failure;
638             }
639         }
640         break;
641       case SSH2_AGENTC_ADD_IDENTITY:
642         /*
643          * Add to the list and return SSH_AGENT_SUCCESS, or
644          * SSH_AGENT_FAILURE if the key was malformed.
645          */
646         {
647             struct ssh2_userkey *key;
648             char *comment;
649             const char *alg;
650             int alglen, commlen;
651             int bloblen;
652
653             plog(logctx, logfn, "request: SSH2_AGENTC_ADD_IDENTITY");
654
655             if (msgend < p+4) {
656                 fail_reason = "request truncated before key algorithm";
657                 goto failure;
658             }
659             alglen = toint(GET_32BIT(p));
660             p += 4;
661             if (alglen < 0 || alglen > msgend - p) {
662                 fail_reason = "request truncated before key algorithm";
663                 goto failure;
664             }
665             alg = (const char *)p;
666             p += alglen;
667
668             key = snew(struct ssh2_userkey);
669             key->alg = find_pubkey_alg_len(alglen, alg);
670             if (!key->alg) {
671                 sfree(key);
672                 fail_reason = "algorithm unknown";
673                 goto failure;
674             }
675
676             bloblen = msgend - p;
677             key->data = key->alg->openssh_createkey(key->alg, &p, &bloblen);
678             if (!key->data) {
679                 sfree(key);
680                 fail_reason = "key setup failed";
681                 goto failure;
682             }
683
684             /*
685              * p has been advanced by openssh_createkey, but
686              * certainly not _beyond_ the end of the buffer.
687              */
688             assert(p <= msgend);
689
690             if (msgend < p+4) {
691                 key->alg->freekey(key->data);
692                 sfree(key);
693                 fail_reason = "request truncated before key comment";
694                 goto failure;
695             }
696             commlen = toint(GET_32BIT(p));
697             p += 4;
698
699             if (commlen < 0 || commlen > msgend - p) {
700                 key->alg->freekey(key->data);
701                 sfree(key);
702                 fail_reason = "request truncated before key comment";
703                 goto failure;
704             }
705             comment = snewn(commlen + 1, char);
706             if (comment) {
707                 memcpy(comment, p, commlen);
708                 comment[commlen] = '\0';
709             }
710             key->comment = comment;
711
712             if (logfn) {
713                 char *fingerprint = ssh2_fingerprint(key->alg, key->data);
714                 plog(logctx, logfn, "submitted key: %s %s",
715                      fingerprint, key->comment);
716                 sfree(fingerprint);
717             }
718
719             if (add234(ssh2keys, key) == key) {
720                 keylist_update();
721                 PUT_32BIT(ret, 1);
722                 ret[4] = SSH_AGENT_SUCCESS;
723
724                 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
725             } else {
726                 key->alg->freekey(key->data);
727                 sfree(key->comment);
728                 sfree(key);
729
730                 fail_reason = "key already present";
731                 goto failure;
732             }
733         }
734         break;
735       case SSH1_AGENTC_REMOVE_RSA_IDENTITY:
736         /*
737          * Remove from the list and return SSH_AGENT_SUCCESS, or
738          * perhaps SSH_AGENT_FAILURE if it wasn't in the list to
739          * start with.
740          */
741         {
742             struct RSAKey reqkey, *key;
743             int n;
744
745             plog(logctx, logfn, "request: SSH1_AGENTC_REMOVE_RSA_IDENTITY");
746
747             n = makekey(p, msgend - p, &reqkey, NULL, 0);
748             if (n < 0) {
749                 fail_reason = "request truncated before public key";
750                 goto failure;
751             }
752
753             if (logfn) {
754                 char fingerprint[128];
755                 reqkey.comment = NULL;
756                 rsa_fingerprint(fingerprint, sizeof(fingerprint), &reqkey);
757                 plog(logctx, logfn, "unwanted key: %s", fingerprint);
758             }
759
760             key = find234(rsakeys, &reqkey, NULL);
761             freebn(reqkey.exponent);
762             freebn(reqkey.modulus);
763             PUT_32BIT(ret, 1);
764             if (key) {
765                 plog(logctx, logfn, "found with comment: %s", key->comment);
766
767                 del234(rsakeys, key);
768                 keylist_update();
769                 freersakey(key);
770                 sfree(key);
771                 ret[4] = SSH_AGENT_SUCCESS;
772
773                 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
774             } else {
775                 fail_reason = "key not found";
776                 goto failure;
777             }
778         }
779         break;
780       case SSH2_AGENTC_REMOVE_IDENTITY:
781         /*
782          * Remove from the list and return SSH_AGENT_SUCCESS, or
783          * perhaps SSH_AGENT_FAILURE if it wasn't in the list to
784          * start with.
785          */
786         {
787             struct ssh2_userkey *key;
788             struct blob b;
789
790             plog(logctx, logfn, "request: SSH2_AGENTC_REMOVE_IDENTITY");
791
792             if (msgend < p+4) {
793                 fail_reason = "request truncated before public key";
794                 goto failure;
795             }
796             b.len = toint(GET_32BIT(p));
797             p += 4;
798
799             if (b.len < 0 || b.len > msgend - p) {
800                 fail_reason = "request truncated before public key";
801                 goto failure;
802             }
803             b.blob = p;
804             p += b.len;
805
806             if (logfn) {
807                 char *fingerprint = ssh2_fingerprint_blob(b.blob, b.len);
808                 plog(logctx, logfn, "unwanted key: %s", fingerprint);
809                 sfree(fingerprint);
810             }
811
812             key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm);
813             if (!key) {
814                 fail_reason = "key not found";
815                 goto failure;
816             }
817
818             plog(logctx, logfn, "found with comment: %s", key->comment);
819
820             del234(ssh2keys, key);
821             keylist_update();
822             key->alg->freekey(key->data);
823             sfree(key);
824             PUT_32BIT(ret, 1);
825             ret[4] = SSH_AGENT_SUCCESS;
826
827             plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
828         }
829         break;
830       case SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
831         /*
832          * Remove all SSH-1 keys. Always returns success.
833          */
834         {
835             struct RSAKey *rkey;
836
837             plog(logctx, logfn, "request:"
838                 " SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES");
839
840             while ((rkey = index234(rsakeys, 0)) != NULL) {
841                 del234(rsakeys, rkey);
842                 freersakey(rkey);
843                 sfree(rkey);
844             }
845             keylist_update();
846
847             PUT_32BIT(ret, 1);
848             ret[4] = SSH_AGENT_SUCCESS;
849
850             plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
851         }
852         break;
853       case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
854         /*
855          * Remove all SSH-2 keys. Always returns success.
856          */
857         {
858             struct ssh2_userkey *skey;
859
860             plog(logctx, logfn, "request: SSH2_AGENTC_REMOVE_ALL_IDENTITIES");
861
862             while ((skey = index234(ssh2keys, 0)) != NULL) {
863                 del234(ssh2keys, skey);
864                 skey->alg->freekey(skey->data);
865                 sfree(skey);
866             }
867             keylist_update();
868
869             PUT_32BIT(ret, 1);
870             ret[4] = SSH_AGENT_SUCCESS;
871
872             plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
873         }
874         break;
875       default:
876         plog(logctx, logfn, "request: unknown message type %d", type);
877
878         fail_reason = "unrecognised message";
879         /* fall through */
880       failure:
881         /*
882          * Unrecognised message. Return SSH_AGENT_FAILURE.
883          */
884         PUT_32BIT(ret, 1);
885         ret[4] = SSH_AGENT_FAILURE;
886         plog(logctx, logfn, "reply: SSH_AGENT_FAILURE (%s)", fail_reason);
887         break;
888     }
889
890     *outlen = 4 + GET_32BIT(ret);
891     return ret;
892 }
893
894 void *pageant_failure_msg(int *outlen)
895 {
896     unsigned char *ret = snewn(5, unsigned char);
897     PUT_32BIT(ret, 1);
898     ret[4] = SSH_AGENT_FAILURE;
899     *outlen = 5;
900     return ret;
901 }
902
903 void pageant_init(void)
904 {
905     pageant_local = TRUE;
906     rsakeys = newtree234(cmpkeys_rsa);
907     ssh2keys = newtree234(cmpkeys_ssh2);
908 }
909
910 struct RSAKey *pageant_nth_ssh1_key(int i)
911 {
912     return index234(rsakeys, i);
913 }
914
915 struct ssh2_userkey *pageant_nth_ssh2_key(int i)
916 {
917     return index234(ssh2keys, i);
918 }
919
920 int pageant_count_ssh1_keys(void)
921 {
922     return count234(rsakeys);
923 }
924
925 int pageant_count_ssh2_keys(void)
926 {
927     return count234(ssh2keys);
928 }
929
930 int pageant_add_ssh1_key(struct RSAKey *rkey)
931 {
932     return add234(rsakeys, rkey) == rkey;
933 }
934
935 int pageant_add_ssh2_key(struct ssh2_userkey *skey)
936 {
937     return add234(ssh2keys, skey) == skey;
938 }
939
940 int pageant_delete_ssh1_key(struct RSAKey *rkey)
941 {
942     struct RSAKey *deleted = del234(rsakeys, rkey);
943     if (!deleted)
944         return FALSE;
945     assert(deleted == rkey);
946     return TRUE;
947 }
948
949 int pageant_delete_ssh2_key(struct ssh2_userkey *skey)
950 {
951     struct ssh2_userkey *deleted = del234(ssh2keys, skey);
952     if (!deleted)
953         return FALSE;
954     assert(deleted == skey);
955     return TRUE;
956 }
957
958 /* ----------------------------------------------------------------------
959  * The agent plug.
960  */
961
962 /*
963  * Coroutine macros similar to, but simplified from, those in ssh.c.
964  */
965 #define crBegin(v)      { int *crLine = &v; switch(v) { case 0:;
966 #define crFinish(z)     } *crLine = 0; return (z); }
967 #define crGetChar(c) do                                         \
968     {                                                           \
969         while (len == 0) {                                      \
970             *crLine =__LINE__; return 1; case __LINE__:;        \
971         }                                                       \
972         len--;                                                  \
973         (c) = (unsigned char)*data++;                           \
974     } while (0)
975
976 struct pageant_conn_state {
977     const struct plug_function_table *fn;
978     /* the above variable absolutely *must* be the first in this structure */
979
980     Socket connsock;
981     void *logctx;
982     pageant_logfn_t logfn;
983     unsigned char lenbuf[4], pktbuf[AGENT_MAX_MSGLEN];
984     unsigned len, got;
985     int real_packet;
986     int crLine;            /* for coroutine in pageant_conn_receive */
987 };
988
989 static int pageant_conn_closing(Plug plug, const char *error_msg,
990                                 int error_code, int calling_back)
991 {
992     struct pageant_conn_state *pc = (struct pageant_conn_state *)plug;
993     if (error_msg)
994         plog(pc->logctx, pc->logfn, "%p: error: %s", pc, error_msg);
995     else
996         plog(pc->logctx, pc->logfn, "%p: connection closed", pc);
997     sk_close(pc->connsock);
998     sfree(pc);
999     return 1;
1000 }
1001
1002 static void pageant_conn_sent(Plug plug, int bufsize)
1003 {
1004     /* struct pageant_conn_state *pc = (struct pageant_conn_state *)plug; */
1005
1006     /*
1007      * We do nothing here, because we expect that there won't be a
1008      * need to throttle and unthrottle the connection to an agent -
1009      * clients will typically not send many requests, and will wait
1010      * until they receive each reply before sending a new request.
1011      */
1012 }
1013
1014 static void pageant_conn_log(void *logctx, const char *fmt, va_list ap)
1015 {
1016     /* Wrapper on pc->logfn that prefixes the connection identifier */
1017     struct pageant_conn_state *pc = (struct pageant_conn_state *)logctx;
1018     char *formatted = dupvprintf(fmt, ap);
1019     plog(pc->logctx, pc->logfn, "%p: %s", pc, formatted);
1020     sfree(formatted);
1021 }
1022
1023 static int pageant_conn_receive(Plug plug, int urgent, char *data, int len)
1024 {
1025     struct pageant_conn_state *pc = (struct pageant_conn_state *)plug;
1026     char c;
1027
1028     crBegin(pc->crLine);
1029
1030     while (len > 0) {
1031         pc->got = 0;
1032         while (pc->got < 4) {
1033             crGetChar(c);
1034             pc->lenbuf[pc->got++] = c;
1035         }
1036
1037         pc->len = GET_32BIT(pc->lenbuf);
1038         pc->got = 0;
1039         pc->real_packet = (pc->len < AGENT_MAX_MSGLEN-4);
1040
1041         while (pc->got < pc->len) {
1042             crGetChar(c);
1043             if (pc->real_packet)
1044                 pc->pktbuf[pc->got] = c;
1045             pc->got++;
1046         }
1047
1048         {
1049             void *reply;
1050             int replylen;
1051
1052             if (pc->real_packet) {
1053                 reply = pageant_handle_msg(pc->pktbuf, pc->len, &replylen, pc,
1054                                            pc->logfn?pageant_conn_log:NULL);
1055             } else {
1056                 plog(pc->logctx, pc->logfn, "%p: overlong message (%u)",
1057                      pc, pc->len);
1058                 plog(pc->logctx, pc->logfn, "%p: reply: SSH_AGENT_FAILURE "
1059                      "(message too long)", pc);
1060                 reply = pageant_failure_msg(&replylen);
1061             }
1062             sk_write(pc->connsock, reply, replylen);
1063             smemclr(reply, replylen);
1064         }
1065     }
1066
1067     crFinish(1);
1068 }
1069
1070 struct pageant_listen_state {
1071     const struct plug_function_table *fn;
1072     /* the above variable absolutely *must* be the first in this structure */
1073
1074     Socket listensock;
1075     void *logctx;
1076     pageant_logfn_t logfn;
1077 };
1078
1079 static int pageant_listen_closing(Plug plug, const char *error_msg,
1080                                   int error_code, int calling_back)
1081 {
1082     struct pageant_listen_state *pl = (struct pageant_listen_state *)plug;
1083     if (error_msg)
1084         plog(pl->logctx, pl->logfn, "listening socket: error: %s", error_msg);
1085     sk_close(pl->listensock);
1086     pl->listensock = NULL;
1087     return 1;
1088 }
1089
1090 static int pageant_listen_accepting(Plug plug,
1091                                     accept_fn_t constructor, accept_ctx_t ctx)
1092 {
1093     static const struct plug_function_table connection_fn_table = {
1094         NULL, /* no log function, because that's for outgoing connections */
1095         pageant_conn_closing,
1096         pageant_conn_receive,
1097         pageant_conn_sent,
1098         NULL /* no accepting function, because we've already done it */
1099     };
1100     struct pageant_listen_state *pl = (struct pageant_listen_state *)plug;
1101     struct pageant_conn_state *pc;
1102     const char *err;
1103     char *peerinfo;
1104
1105     pc = snew(struct pageant_conn_state);
1106     pc->fn = &connection_fn_table;
1107     pc->logfn = pl->logfn;
1108     pc->logctx = pl->logctx;
1109     pc->crLine = 0;
1110
1111     pc->connsock = constructor(ctx, (Plug) pc);
1112     if ((err = sk_socket_error(pc->connsock)) != NULL) {
1113         sk_close(pc->connsock);
1114         sfree(pc);
1115         return TRUE;
1116     }
1117
1118     sk_set_frozen(pc->connsock, 0);
1119
1120     peerinfo = sk_peer_info(pc->connsock);
1121     if (peerinfo) {
1122         plog(pl->logctx, pl->logfn, "%p: new connection from %s",
1123              pc, peerinfo);
1124     } else {
1125         plog(pl->logctx, pl->logfn, "%p: new connection", pc);
1126     }
1127
1128     return 0;
1129 }
1130
1131 struct pageant_listen_state *pageant_listener_new(void)
1132 {
1133     static const struct plug_function_table listener_fn_table = {
1134         NULL, /* no log function, because that's for outgoing connections */
1135         pageant_listen_closing,
1136         NULL, /* no receive function on a listening socket */
1137         NULL, /* no sent function on a listening socket */
1138         pageant_listen_accepting
1139     };
1140
1141     struct pageant_listen_state *pl = snew(struct pageant_listen_state);
1142     pl->fn = &listener_fn_table;
1143     pl->logctx = NULL;
1144     pl->logfn = NULL;
1145     pl->listensock = NULL;
1146     return pl;
1147 }
1148
1149 void pageant_listener_got_socket(struct pageant_listen_state *pl, Socket sock)
1150 {
1151     pl->listensock = sock;
1152 }
1153
1154 void pageant_listener_set_logfn(struct pageant_listen_state *pl,
1155                                 void *logctx, pageant_logfn_t logfn)
1156 {
1157     pl->logctx = logctx;
1158     pl->logfn = logfn;
1159 }
1160
1161 void pageant_listener_free(struct pageant_listen_state *pl)
1162 {
1163     if (pl->listensock)
1164         sk_close(pl->listensock);
1165     sfree(pl);
1166 }
1167
1168 /* ----------------------------------------------------------------------
1169  * Code to perform agent operations either as a client, or within the
1170  * same process as the running agent.
1171  */
1172
1173 static tree234 *passphrases = NULL;
1174
1175 /*
1176  * After processing a list of filenames, we want to forget the
1177  * passphrases.
1178  */
1179 void pageant_forget_passphrases(void)
1180 {
1181     if (!passphrases)                  /* in case we never set it up at all */
1182         return;
1183
1184     while (count234(passphrases) > 0) {
1185         char *pp = index234(passphrases, 0);
1186         smemclr(pp, strlen(pp));
1187         delpos234(passphrases, 0);
1188         free(pp);
1189     }
1190 }
1191
1192 void *pageant_get_keylist1(int *length)
1193 {
1194     void *ret;
1195
1196     if (!pageant_local) {
1197         unsigned char request[5], *response;
1198         void *vresponse;
1199         int resplen, retval;
1200         request[4] = SSH1_AGENTC_REQUEST_RSA_IDENTITIES;
1201         PUT_32BIT(request, 1);
1202
1203         retval = agent_query(request, 5, &vresponse, &resplen, NULL, NULL);
1204         assert(retval == 1);
1205         response = vresponse;
1206         if (resplen < 5 || response[4] != SSH1_AGENT_RSA_IDENTITIES_ANSWER) {
1207             sfree(response);
1208             return NULL;
1209         }
1210
1211         ret = snewn(resplen-5, unsigned char);
1212         memcpy(ret, response+5, resplen-5);
1213         sfree(response);
1214
1215         if (length)
1216             *length = resplen-5;
1217     } else {
1218         ret = pageant_make_keylist1(length);
1219     }
1220     return ret;
1221 }
1222
1223 void *pageant_get_keylist2(int *length)
1224 {
1225     void *ret;
1226
1227     if (!pageant_local) {
1228         unsigned char request[5], *response;
1229         void *vresponse;
1230         int resplen, retval;
1231
1232         request[4] = SSH2_AGENTC_REQUEST_IDENTITIES;
1233         PUT_32BIT(request, 1);
1234
1235         retval = agent_query(request, 5, &vresponse, &resplen, NULL, NULL);
1236         assert(retval == 1);
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                 return PAGEANT_ACTION_FAILURE;
1317             }
1318             nkeys = toint(GET_32BIT(keylist));
1319             if (nkeys < 0) {
1320                 *retstr = dupstr("Received broken key list from agent");
1321                 return PAGEANT_ACTION_FAILURE;
1322             }
1323             p = keylist + 4;
1324             keylistlen -= 4;
1325
1326             for (i = 0; i < nkeys; i++) {
1327                 if (!memcmp(blob, p, bloblen)) {
1328                     /* Key is already present; we can now leave. */
1329                     sfree(keylist);
1330                     sfree(blob);
1331                     return PAGEANT_ACTION_OK;
1332                 }
1333                 /* Now skip over public blob */
1334                 if (type == SSH_KEYTYPE_SSH1) {
1335                     int n = rsa_public_blob_len(p, keylistlen);
1336                     if (n < 0) {
1337                         *retstr = dupstr("Received broken key list from agent");
1338                         return PAGEANT_ACTION_FAILURE;
1339                     }
1340                     p += n;
1341                     keylistlen -= n;
1342                 } else {
1343                     int n;
1344                     if (keylistlen < 4) {
1345                         *retstr = dupstr("Received broken key list from agent");
1346                         return PAGEANT_ACTION_FAILURE;
1347                     }
1348                     n = toint(4 + GET_32BIT(p));
1349                     if (n < 0 || keylistlen < n) {
1350                         *retstr = dupstr("Received broken key list from agent");
1351                         return PAGEANT_ACTION_FAILURE;
1352                     }
1353                     p += n;
1354                     keylistlen -= n;
1355                 }
1356                 /* Now skip over comment field */
1357                 {
1358                     int n;
1359                     if (keylistlen < 4) {
1360                         *retstr = dupstr("Received broken key list from agent");
1361                         return PAGEANT_ACTION_FAILURE;
1362                     }
1363                     n = toint(4 + GET_32BIT(p));
1364                     if (n < 0 || keylistlen < n) {
1365                         *retstr = dupstr("Received broken key list from agent");
1366                         return PAGEANT_ACTION_FAILURE;
1367                     }
1368                     p += n;
1369                     keylistlen -= n;
1370                 }
1371             }
1372
1373             sfree(keylist);
1374         }
1375
1376         sfree(blob);
1377     }
1378
1379     error = NULL;
1380     if (type == SSH_KEYTYPE_SSH1)
1381         needs_pass = rsakey_encrypted(filename, &comment);
1382     else
1383         needs_pass = ssh2_userkey_encrypted(filename, &comment);
1384     attempts = 0;
1385     if (type == SSH_KEYTYPE_SSH1)
1386         rkey = snew(struct RSAKey);
1387
1388     /*
1389      * Loop round repeatedly trying to load the key, until we either
1390      * succeed, fail for some serious reason, or run out of
1391      * passphrases to try.
1392      */
1393     while (1) {
1394         if (needs_pass) {
1395
1396             /*
1397              * If we've been given a passphrase on input, try using
1398              * it. Otherwise, try one from our tree234 of previously
1399              * useful passphrases.
1400              */
1401             if (passphrase) {
1402                 this_passphrase = (attempts == 0 ? passphrase : NULL);
1403             } else {
1404                 this_passphrase = (const char *)index234(passphrases, attempts);
1405             }
1406
1407             if (!this_passphrase) {
1408                 /*
1409                  * Run out of passphrases to try.
1410                  */
1411                 *retstr = comment;
1412                 return PAGEANT_ACTION_NEED_PP;
1413             }
1414         } else
1415             this_passphrase = "";
1416
1417         if (type == SSH_KEYTYPE_SSH1)
1418             ret = loadrsakey(filename, rkey, this_passphrase, &error);
1419         else {
1420             skey = ssh2_load_userkey(filename, this_passphrase, &error);
1421             if (skey == SSH2_WRONG_PASSPHRASE)
1422                 ret = -1;
1423             else if (!skey)
1424                 ret = 0;
1425             else
1426                 ret = 1;
1427         }
1428
1429         if (ret == 0) {
1430             /*
1431              * Failed to load the key file, for some reason other than
1432              * a bad passphrase.
1433              */
1434             *retstr = dupstr(error);
1435             return PAGEANT_ACTION_FAILURE;
1436         } else if (ret == 1) {
1437             /*
1438              * Successfully loaded the key file.
1439              */
1440             break;
1441         } else {
1442             /*
1443              * Passphrase wasn't right; go round again.
1444              */
1445             attempts++;
1446         }
1447     }
1448
1449     /*
1450      * If we get here, we've succesfully loaded the key into
1451      * rkey/skey, but not yet added it to the agent.
1452      */
1453
1454     /*
1455      * If the key was successfully decrypted, save the passphrase for
1456      * use with other keys we try to load.
1457      */
1458     {
1459         char *pp_copy = dupstr(this_passphrase);
1460         if (addpos234(passphrases, pp_copy, 0) != pp_copy) {
1461             /* No need; it was already there. */
1462             smemclr(pp_copy, strlen(pp_copy));
1463             sfree(pp_copy);
1464         }
1465     }
1466
1467     if (comment)
1468         sfree(comment);
1469
1470     if (type == SSH_KEYTYPE_SSH1) {
1471         if (!pageant_local) {
1472             unsigned char *request, *response;
1473             void *vresponse;
1474             int reqlen, clen, resplen, ret;
1475
1476             clen = strlen(rkey->comment);
1477
1478             reqlen = 4 + 1 +           /* length, message type */
1479                 4 +                    /* bit count */
1480                 ssh1_bignum_length(rkey->modulus) +
1481                 ssh1_bignum_length(rkey->exponent) +
1482                 ssh1_bignum_length(rkey->private_exponent) +
1483                 ssh1_bignum_length(rkey->iqmp) +
1484                 ssh1_bignum_length(rkey->p) +
1485                 ssh1_bignum_length(rkey->q) + 4 + clen  /* comment */
1486                 ;
1487
1488             request = snewn(reqlen, unsigned char);
1489
1490             request[4] = SSH1_AGENTC_ADD_RSA_IDENTITY;
1491             reqlen = 5;
1492             PUT_32BIT(request + reqlen, bignum_bitcount(rkey->modulus));
1493             reqlen += 4;
1494             reqlen += ssh1_write_bignum(request + reqlen, rkey->modulus);
1495             reqlen += ssh1_write_bignum(request + reqlen, rkey->exponent);
1496             reqlen +=
1497                 ssh1_write_bignum(request + reqlen,
1498                                   rkey->private_exponent);
1499             reqlen += ssh1_write_bignum(request + reqlen, rkey->iqmp);
1500             reqlen += ssh1_write_bignum(request + reqlen, rkey->p);
1501             reqlen += ssh1_write_bignum(request + reqlen, rkey->q);
1502             PUT_32BIT(request + reqlen, clen);
1503             memcpy(request + reqlen + 4, rkey->comment, clen);
1504             reqlen += 4 + clen;
1505             PUT_32BIT(request, reqlen - 4);
1506
1507             ret = agent_query(request, reqlen, &vresponse, &resplen,
1508                               NULL, NULL);
1509             assert(ret == 1);
1510             response = vresponse;
1511             if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
1512                 *retstr = dupstr("The already running Pageant "
1513                                  "refused to add the key.");
1514                 return PAGEANT_ACTION_FAILURE;
1515             }
1516             sfree(request);
1517             sfree(response);
1518         } else {
1519             if (!pageant_add_ssh1_key(rkey)) {
1520                 sfree(rkey);           /* already present, don't waste RAM */
1521             }
1522         }
1523     } else {
1524         if (!pageant_local) {
1525             unsigned char *request, *response;
1526             void *vresponse;
1527             int reqlen, alglen, clen, keybloblen, resplen, ret;
1528             alglen = strlen(skey->alg->name);
1529             clen = strlen(skey->comment);
1530
1531             keybloblen = skey->alg->openssh_fmtkey(skey->data, NULL, 0);
1532
1533             reqlen = 4 + 1 +           /* length, message type */
1534                 4 + alglen +           /* algorithm name */
1535                 keybloblen +           /* key data */
1536                 4 + clen               /* comment */
1537                 ;
1538
1539             request = snewn(reqlen, unsigned char);
1540
1541             request[4] = SSH2_AGENTC_ADD_IDENTITY;
1542             reqlen = 5;
1543             PUT_32BIT(request + reqlen, alglen);
1544             reqlen += 4;
1545             memcpy(request + reqlen, skey->alg->name, alglen);
1546             reqlen += alglen;
1547             reqlen += skey->alg->openssh_fmtkey(skey->data,
1548                                                 request + reqlen,
1549                                                 keybloblen);
1550             PUT_32BIT(request + reqlen, clen);
1551             memcpy(request + reqlen + 4, skey->comment, clen);
1552             reqlen += clen + 4;
1553             PUT_32BIT(request, reqlen - 4);
1554
1555             ret = agent_query(request, reqlen, &vresponse, &resplen,
1556                               NULL, NULL);
1557             assert(ret == 1);
1558             response = vresponse;
1559             if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
1560                 *retstr = dupstr("The already running Pageant "
1561                                  "refused to add the key.");
1562                 return PAGEANT_ACTION_FAILURE;
1563             }
1564
1565             sfree(request);
1566             sfree(response);
1567         } else {
1568             if (!pageant_add_ssh2_key(skey)) {
1569                 skey->alg->freekey(skey->data);
1570                 sfree(skey);           /* already present, don't waste RAM */
1571             }
1572         }
1573     }
1574     return PAGEANT_ACTION_OK;
1575 }
1576
1577 int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx,
1578                       char **retstr)
1579 {
1580     unsigned char *keylist, *p;
1581     int i, nkeys, keylistlen;
1582     char *comment;
1583     struct pageant_pubkey cbkey;
1584
1585     keylist = pageant_get_keylist1(&keylistlen);
1586     if (keylistlen < 4) {
1587         *retstr = dupstr("Received broken SSH-1 key list from agent");
1588         sfree(keylist);
1589         return PAGEANT_ACTION_FAILURE;
1590     }
1591     nkeys = toint(GET_32BIT(keylist));
1592     if (nkeys < 0) {
1593         *retstr = dupstr("Received broken SSH-1 key list from agent");
1594         sfree(keylist);
1595         return PAGEANT_ACTION_FAILURE;
1596     }
1597     p = keylist + 4;
1598     keylistlen -= 4;
1599
1600     for (i = 0; i < nkeys; i++) {
1601         struct RSAKey rkey;
1602         char fingerprint[128];
1603         int n;
1604
1605         /* public blob and fingerprint */
1606         memset(&rkey, 0, sizeof(rkey));
1607         n = makekey(p, keylistlen, &rkey, NULL, 0);
1608         if (n < 0 || n > keylistlen) {
1609             freersakey(&rkey);
1610             *retstr = dupstr("Received broken SSH-1 key list from agent");
1611             sfree(keylist);
1612             return PAGEANT_ACTION_FAILURE;
1613         }
1614         p += n, keylistlen -= n;
1615         rsa_fingerprint(fingerprint, sizeof(fingerprint), &rkey);
1616
1617         /* comment */
1618         if (keylistlen < 4) {
1619             *retstr = dupstr("Received broken SSH-1 key list from agent");
1620             freersakey(&rkey);
1621             sfree(keylist);
1622             return PAGEANT_ACTION_FAILURE;
1623         }
1624         n = toint(GET_32BIT(p));
1625         p += 4, keylistlen -= 4;
1626         if (n < 0 || keylistlen < n) {
1627             *retstr = dupstr("Received broken SSH-1 key list from agent");
1628             freersakey(&rkey);
1629             sfree(keylist);
1630             return PAGEANT_ACTION_FAILURE;
1631         }
1632         comment = dupprintf("%.*s", (int)n, (const char *)p);
1633         p += n, keylistlen -= n;
1634
1635         cbkey.blob = rsa_public_blob(&rkey, &cbkey.bloblen);
1636         cbkey.comment = comment;
1637         cbkey.ssh_version = 1;
1638         callback(callback_ctx, fingerprint, comment, &cbkey);
1639         sfree(cbkey.blob);
1640         freersakey(&rkey);
1641         sfree(comment);
1642     }
1643
1644     sfree(keylist);
1645
1646     if (keylistlen != 0) {
1647         *retstr = dupstr("Received broken SSH-1 key list from agent");
1648         return PAGEANT_ACTION_FAILURE;
1649     }
1650
1651     keylist = pageant_get_keylist2(&keylistlen);
1652     if (keylistlen < 4) {
1653         *retstr = dupstr("Received broken SSH-2 key list from agent");
1654         sfree(keylist);
1655         return PAGEANT_ACTION_FAILURE;
1656     }
1657     nkeys = toint(GET_32BIT(keylist));
1658     if (nkeys < 0) {
1659         *retstr = dupstr("Received broken SSH-2 key list from agent");
1660         sfree(keylist);
1661         return PAGEANT_ACTION_FAILURE;
1662     }
1663     p = keylist + 4;
1664     keylistlen -= 4;
1665
1666     for (i = 0; i < nkeys; i++) {
1667         char *fingerprint;
1668         int n;
1669
1670         /* public blob */
1671         if (keylistlen < 4) {
1672             *retstr = dupstr("Received broken SSH-2 key list from agent");
1673             sfree(keylist);
1674             return PAGEANT_ACTION_FAILURE;
1675         }
1676         n = toint(GET_32BIT(p));
1677         p += 4, keylistlen -= 4;
1678         if (n < 0 || keylistlen < n) {
1679             *retstr = dupstr("Received broken SSH-2 key list from agent");
1680             sfree(keylist);
1681             return PAGEANT_ACTION_FAILURE;
1682         }
1683         fingerprint = ssh2_fingerprint_blob(p, n);
1684         cbkey.blob = p;
1685         cbkey.bloblen = n;
1686         p += n, keylistlen -= n;
1687
1688         /* comment */
1689         if (keylistlen < 4) {
1690             *retstr = dupstr("Received broken SSH-2 key list from agent");
1691             sfree(fingerprint);
1692             sfree(keylist);
1693             return PAGEANT_ACTION_FAILURE;
1694         }
1695         n = toint(GET_32BIT(p));
1696         p += 4, keylistlen -= 4;
1697         if (n < 0 || keylistlen < n) {
1698             *retstr = dupstr("Received broken SSH-2 key list from agent");
1699             sfree(fingerprint);
1700             sfree(keylist);
1701             return PAGEANT_ACTION_FAILURE;
1702         }
1703         comment = dupprintf("%.*s", (int)n, (const char *)p);
1704         p += n, keylistlen -= n;
1705
1706         cbkey.ssh_version = 2;
1707         cbkey.comment = comment;
1708         callback(callback_ctx, fingerprint, comment, &cbkey);
1709         sfree(fingerprint);
1710         sfree(comment);
1711     }
1712
1713     sfree(keylist);
1714
1715     if (keylistlen != 0) {
1716         *retstr = dupstr("Received broken SSH-1 key list from agent");
1717         return PAGEANT_ACTION_FAILURE;
1718     }
1719
1720     return PAGEANT_ACTION_OK;
1721 }
1722
1723 int pageant_delete_key(struct pageant_pubkey *key, char **retstr)
1724 {
1725     unsigned char *request, *response;
1726     int reqlen, resplen, ret;
1727     void *vresponse;
1728
1729     if (key->ssh_version == 1) {
1730         reqlen = 5 + key->bloblen;
1731         request = snewn(reqlen, unsigned char);
1732         PUT_32BIT(request, reqlen - 4);
1733         request[4] = SSH1_AGENTC_REMOVE_RSA_IDENTITY;
1734         memcpy(request + 5, key->blob, key->bloblen);
1735     } else {
1736         reqlen = 9 + key->bloblen;
1737         request = snewn(reqlen, unsigned char);
1738         PUT_32BIT(request, reqlen - 4);
1739         request[4] = SSH2_AGENTC_REMOVE_IDENTITY;
1740         PUT_32BIT(request + 5, key->bloblen);
1741         memcpy(request + 9, key->blob, key->bloblen);
1742     }
1743
1744     ret = agent_query(request, reqlen, &vresponse, &resplen, NULL, NULL);
1745     assert(ret == 1);
1746     response = vresponse;
1747     if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
1748         *retstr = dupstr("Agent failed to delete key");
1749         ret = PAGEANT_ACTION_FAILURE;
1750     } else {
1751         *retstr = NULL;
1752         ret = PAGEANT_ACTION_OK;
1753     }
1754     sfree(request);
1755     sfree(response);
1756     return ret;
1757 }
1758
1759 int pageant_delete_all_keys(char **retstr)
1760 {
1761     unsigned char request[5], *response;
1762     int reqlen, resplen, success, ret;
1763     void *vresponse;
1764
1765     PUT_32BIT(request, 1);
1766     request[4] = SSH2_AGENTC_REMOVE_ALL_IDENTITIES;
1767     reqlen = 5;
1768     ret = agent_query(request, reqlen, &vresponse, &resplen, NULL, NULL);
1769     assert(ret == 1);
1770     response = vresponse;
1771     success = (resplen >= 4 && response[4] == SSH_AGENT_SUCCESS);
1772     sfree(response);
1773     if (!success) {
1774         *retstr = dupstr("Agent failed to delete SSH-2 keys");
1775         return PAGEANT_ACTION_FAILURE;
1776     }
1777
1778     PUT_32BIT(request, 1);
1779     request[4] = SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
1780     reqlen = 5;
1781     ret = agent_query(request, reqlen, &vresponse, &resplen, NULL, NULL);
1782     assert(ret == 1);
1783     response = vresponse;
1784     success = (resplen >= 4 && response[4] == SSH_AGENT_SUCCESS);
1785     sfree(response);
1786     if (!success) {
1787         *retstr = dupstr("Agent failed to delete SSH-1 keys");
1788         return PAGEANT_ACTION_FAILURE;
1789     }
1790
1791     *retstr = NULL;
1792     return PAGEANT_ACTION_OK;
1793 }
1794
1795 struct pageant_pubkey *pageant_pubkey_copy(struct pageant_pubkey *key)
1796 {
1797     struct pageant_pubkey *ret = snew(struct pageant_pubkey);
1798     ret->blob = snewn(key->bloblen, unsigned char);
1799     memcpy(ret->blob, key->blob, key->bloblen);
1800     ret->bloblen = key->bloblen;
1801     ret->comment = key->comment ? dupstr(key->comment) : NULL;
1802     ret->ssh_version = key->ssh_version;
1803     return ret;
1804 }
1805
1806 void pageant_pubkey_free(struct pageant_pubkey *key)
1807 {
1808     sfree(key->comment);
1809     sfree(key->blob);
1810     sfree(key);
1811 }