]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - pageant.c
Pageant: factor out cross-platform parts of add_keyfile().
[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 char *fingerprint_ssh2_blob(const void *blob, int bloblen)
263 {
264     unsigned char digest[16];
265     char fingerprint_str[16*3];
266     unsigned stringlen;
267     int i;
268
269     MD5Simple(blob, bloblen, digest);
270     for (i = 0; i < 16; i++)
271         sprintf(fingerprint_str + i*3, "%02x%s", digest[i], i==15 ? "" : ":");
272
273     stringlen = GET_32BIT((const unsigned char *)blob);
274     if (stringlen < bloblen-4)
275         return dupprintf("%.*s %s", (int)stringlen, (const char *)blob + 4,
276                          fingerprint_str);
277     else
278         return dupstr(fingerprint_str);        
279 }
280
281 static void plog(void *logctx, pageant_logfn_t logfn, const char *fmt, ...)
282 #ifdef __GNUC__
283 __attribute__ ((format (printf, 3, 4)))
284 #endif
285     ;
286
287 static void plog(void *logctx, pageant_logfn_t logfn, const char *fmt, ...)
288 {
289     /*
290      * This is the wrapper that takes a variadic argument list and
291      * turns it into the va_list that the log function really expects.
292      * It's safe to call this with logfn==NULL, because we
293      * double-check that below; but if you're going to do lots of work
294      * before getting here (such as looping, or hashing things) then
295      * you should probably check logfn manually before doing that.
296      */
297     if (logfn) {
298         va_list ap;
299         va_start(ap, fmt);
300         logfn(logctx, fmt, ap);
301         va_end(ap);
302     }
303 }
304
305 void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
306                          void *logctx, pageant_logfn_t logfn)
307 {
308     const unsigned char *p = msg;
309     const unsigned char *msgend;
310     unsigned char *ret = snewn(AGENT_MAX_MSGLEN, unsigned char);
311     int type;
312     const char *fail_reason;
313
314     msgend = p + msglen;
315
316     /*
317      * Get the message type.
318      */
319     if (msgend < p+1) {
320         fail_reason = "message contained no type code";
321         goto failure;
322     }
323     type = *p++;
324
325     switch (type) {
326       case SSH1_AGENTC_REQUEST_RSA_IDENTITIES:
327         /*
328          * Reply with SSH1_AGENT_RSA_IDENTITIES_ANSWER.
329          */
330         {
331             int len;
332             void *keylist;
333
334             plog(logctx, logfn, "request: SSH1_AGENTC_REQUEST_RSA_IDENTITIES");
335
336             ret[4] = SSH1_AGENT_RSA_IDENTITIES_ANSWER;
337             keylist = pageant_make_keylist1(&len);
338             if (len + 5 > AGENT_MAX_MSGLEN) {
339                 sfree(keylist);
340                 fail_reason = "output would exceed max msglen";
341                 goto failure;
342             }
343             PUT_32BIT(ret, len + 1);
344             memcpy(ret + 5, keylist, len);
345
346             plog(logctx, logfn, "reply: SSH1_AGENT_RSA_IDENTITIES_ANSWER");
347             if (logfn) {               /* skip this loop if not logging */
348                 int i;
349                 struct RSAKey *rkey;
350                 for (i = 0; NULL != (rkey = pageant_nth_ssh1_key(i)); i++) {
351                     char fingerprint[128];
352                     rsa_fingerprint(fingerprint, sizeof(fingerprint), rkey);
353                     plog(logctx, logfn, "returned key: %s", fingerprint);
354                 }
355             }
356             sfree(keylist);
357         }
358         break;
359       case SSH2_AGENTC_REQUEST_IDENTITIES:
360         /*
361          * Reply with SSH2_AGENT_IDENTITIES_ANSWER.
362          */
363         {
364             int len;
365             void *keylist;
366
367             plog(logctx, logfn, "request: SSH2_AGENTC_REQUEST_IDENTITIES");
368
369             ret[4] = SSH2_AGENT_IDENTITIES_ANSWER;
370             keylist = pageant_make_keylist2(&len);
371             if (len + 5 > AGENT_MAX_MSGLEN) {
372                 sfree(keylist);
373                 fail_reason = "output would exceed max msglen";
374                 goto failure;
375             }
376             PUT_32BIT(ret, len + 1);
377             memcpy(ret + 5, keylist, len);
378
379             plog(logctx, logfn, "reply: SSH2_AGENT_IDENTITIES_ANSWER");
380             if (logfn) {               /* skip this loop if not logging */
381                 int i;
382                 struct ssh2_userkey *skey;
383                 for (i = 0; NULL != (skey = pageant_nth_ssh2_key(i)); i++) {
384                     char *fingerprint = skey->alg->fingerprint(skey->data);
385                     plog(logctx, logfn, "returned key: %s %s",
386                          fingerprint, skey->comment);
387                     sfree(fingerprint);
388                 }
389             }
390
391             sfree(keylist);
392         }
393         break;
394       case SSH1_AGENTC_RSA_CHALLENGE:
395         /*
396          * Reply with either SSH1_AGENT_RSA_RESPONSE or
397          * SSH_AGENT_FAILURE, depending on whether we have that key
398          * or not.
399          */
400         {
401             struct RSAKey reqkey, *key;
402             Bignum challenge, response;
403             unsigned char response_source[48], response_md5[16];
404             struct MD5Context md5c;
405             int i, len;
406
407             plog(logctx, logfn, "request: SSH1_AGENTC_RSA_CHALLENGE");
408
409             p += 4;
410             i = ssh1_read_bignum(p, msgend - p, &reqkey.exponent);
411             if (i < 0) {
412                 fail_reason = "request truncated before key exponent";
413                 goto failure;
414             }
415             p += i;
416             i = ssh1_read_bignum(p, msgend - p, &reqkey.modulus);
417             if (i < 0) {
418                 freebn(reqkey.exponent);
419                 fail_reason = "request truncated before key modulus";
420                 goto failure;
421             }
422             p += i;
423             i = ssh1_read_bignum(p, msgend - p, &challenge);
424             if (i < 0) {
425                 freebn(reqkey.exponent);
426                 freebn(reqkey.modulus);
427                 fail_reason = "request truncated before challenge";
428                 goto failure;
429             }
430             p += i;
431             if (msgend < p+16) {
432                 freebn(reqkey.exponent);
433                 freebn(reqkey.modulus);
434                 freebn(challenge);
435                 fail_reason = "request truncated before session id";
436                 goto failure;
437             }
438             memcpy(response_source + 32, p, 16);
439             p += 16;
440             if (msgend < p+4) {
441                 freebn(reqkey.exponent);
442                 freebn(reqkey.modulus);
443                 freebn(challenge);
444                 fail_reason = "request truncated before response type";
445                 goto failure;
446             }
447             if (GET_32BIT(p) != 1) {
448                 freebn(reqkey.exponent);
449                 freebn(reqkey.modulus);
450                 freebn(challenge);
451                 fail_reason = "response type other than 1 not supported";
452                 goto failure;
453             }
454             if (logfn) {
455                 char fingerprint[128];
456                 reqkey.comment = NULL;
457                 rsa_fingerprint(fingerprint, sizeof(fingerprint), &reqkey);
458                 plog(logctx, logfn, "requested key: %s", fingerprint);
459             }
460             if ((key = find234(rsakeys, &reqkey, NULL)) == NULL) {
461                 freebn(reqkey.exponent);
462                 freebn(reqkey.modulus);
463                 freebn(challenge);
464                 fail_reason = "key not found";
465                 goto failure;
466             }
467             response = rsadecrypt(challenge, key);
468             for (i = 0; i < 32; i++)
469                 response_source[i] = bignum_byte(response, 31 - i);
470
471             MD5Init(&md5c);
472             MD5Update(&md5c, response_source, 48);
473             MD5Final(response_md5, &md5c);
474             smemclr(response_source, 48);       /* burn the evidence */
475             freebn(response);          /* and that evidence */
476             freebn(challenge);         /* yes, and that evidence */
477             freebn(reqkey.exponent);   /* and free some memory ... */
478             freebn(reqkey.modulus);    /* ... while we're at it. */
479
480             /*
481              * Packet is the obvious five byte header, plus sixteen
482              * bytes of MD5.
483              */
484             len = 5 + 16;
485             PUT_32BIT(ret, len - 4);
486             ret[4] = SSH1_AGENT_RSA_RESPONSE;
487             memcpy(ret + 5, response_md5, 16);
488
489             plog(logctx, logfn, "reply: SSH1_AGENT_RSA_RESPONSE");
490         }
491         break;
492       case SSH2_AGENTC_SIGN_REQUEST:
493         /*
494          * Reply with either SSH2_AGENT_SIGN_RESPONSE or
495          * SSH_AGENT_FAILURE, depending on whether we have that key
496          * or not.
497          */
498         {
499             struct ssh2_userkey *key;
500             struct blob b;
501             const unsigned char *data;
502             unsigned char *signature;
503             int datalen, siglen, len;
504
505             plog(logctx, logfn, "request: SSH2_AGENTC_SIGN_REQUEST");
506
507             if (msgend < p+4) {
508                 fail_reason = "request truncated before public key";
509                 goto failure;
510             }
511             b.len = toint(GET_32BIT(p));
512             if (b.len < 0 || b.len > msgend - (p+4)) {
513                 fail_reason = "request truncated before public key";
514                 goto failure;
515             }
516             p += 4;
517             b.blob = p;
518             p += b.len;
519             if (msgend < p+4) {
520                 fail_reason = "request truncated before string to sign";
521                 goto failure;
522             }
523             datalen = toint(GET_32BIT(p));
524             p += 4;
525             if (datalen < 0 || datalen > msgend - p) {
526                 fail_reason = "request truncated before string to sign";
527                 goto failure;
528             }
529             data = p;
530             if (logfn) {
531                 char *fingerprint = fingerprint_ssh2_blob(b.blob, b.len);
532                 plog(logctx, logfn, "requested key: %s", fingerprint);
533                 sfree(fingerprint);
534             }
535             key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm);
536             if (!key) {
537                 fail_reason = "key not found";
538                 goto failure;
539             }
540             signature = key->alg->sign(key->data, (const char *)data,
541                                        datalen, &siglen);
542             len = 5 + 4 + siglen;
543             PUT_32BIT(ret, len - 4);
544             ret[4] = SSH2_AGENT_SIGN_RESPONSE;
545             PUT_32BIT(ret + 5, siglen);
546             memcpy(ret + 5 + 4, signature, siglen);
547             sfree(signature);
548
549             plog(logctx, logfn, "reply: SSH2_AGENT_SIGN_RESPONSE");
550         }
551         break;
552       case SSH1_AGENTC_ADD_RSA_IDENTITY:
553         /*
554          * Add to the list and return SSH_AGENT_SUCCESS, or
555          * SSH_AGENT_FAILURE if the key was malformed.
556          */
557         {
558             struct RSAKey *key;
559             char *comment;
560             int n, commentlen;
561
562             plog(logctx, logfn, "request: SSH1_AGENTC_ADD_RSA_IDENTITY");
563
564             key = snew(struct RSAKey);
565             memset(key, 0, sizeof(struct RSAKey));
566
567             n = makekey(p, msgend - p, key, NULL, 1);
568             if (n < 0) {
569                 freersakey(key);
570                 sfree(key);
571                 fail_reason = "request truncated before public key";
572                 goto failure;
573             }
574             p += n;
575
576             n = makeprivate(p, msgend - p, key);
577             if (n < 0) {
578                 freersakey(key);
579                 sfree(key);
580                 fail_reason = "request truncated before private key";
581                 goto failure;
582             }
583             p += n;
584
585             /* SSH-1 names p and q the other way round, i.e. we have
586              * the inverse of p mod q and not of q mod p. We swap the
587              * names, because our internal RSA wants iqmp. */
588
589             n = ssh1_read_bignum(p, msgend - p, &key->iqmp);  /* p^-1 mod q */
590             if (n < 0) {
591                 freersakey(key);
592                 sfree(key);
593                 fail_reason = "request truncated before iqmp";
594                 goto failure;
595             }
596             p += n;
597
598             n = ssh1_read_bignum(p, msgend - p, &key->q);  /* p */
599             if (n < 0) {
600                 freersakey(key);
601                 sfree(key);
602                 fail_reason = "request truncated before p";
603                 goto failure;
604             }
605             p += n;
606
607             n = ssh1_read_bignum(p, msgend - p, &key->p);  /* q */
608             if (n < 0) {
609                 freersakey(key);
610                 sfree(key);
611                 fail_reason = "request truncated before q";
612                 goto failure;
613             }
614             p += n;
615
616             if (msgend < p+4) {
617                 freersakey(key);
618                 sfree(key);
619                 fail_reason = "request truncated before key comment";
620                 goto failure;
621             }
622             commentlen = toint(GET_32BIT(p));
623
624             if (commentlen < 0 || commentlen > msgend - p) {
625                 freersakey(key);
626                 sfree(key);
627                 fail_reason = "request truncated before key comment";
628                 goto failure;
629             }
630
631             comment = snewn(commentlen+1, char);
632             if (comment) {
633                 memcpy(comment, p + 4, commentlen);
634                 comment[commentlen] = '\0';
635                 key->comment = comment;
636             }
637
638             if (logfn) {
639                 char fingerprint[128];
640                 rsa_fingerprint(fingerprint, sizeof(fingerprint), key);
641                 plog(logctx, logfn, "submitted key: %s", fingerprint);
642             }
643
644             if (add234(rsakeys, key) == key) {
645                 keylist_update();
646                 PUT_32BIT(ret, 1);
647                 ret[4] = SSH_AGENT_SUCCESS;
648
649                 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
650             } else {
651                 freersakey(key);
652                 sfree(key);
653
654                 fail_reason = "key already present";
655                 goto failure;
656             }
657         }
658         break;
659       case SSH2_AGENTC_ADD_IDENTITY:
660         /*
661          * Add to the list and return SSH_AGENT_SUCCESS, or
662          * SSH_AGENT_FAILURE if the key was malformed.
663          */
664         {
665             struct ssh2_userkey *key;
666             char *comment;
667             const char *alg;
668             int alglen, commlen;
669             int bloblen;
670
671             plog(logctx, logfn, "request: SSH2_AGENTC_ADD_IDENTITY");
672
673             if (msgend < p+4) {
674                 fail_reason = "request truncated before key algorithm";
675                 goto failure;
676             }
677             alglen = toint(GET_32BIT(p));
678             p += 4;
679             if (alglen < 0 || alglen > msgend - p) {
680                 fail_reason = "request truncated before key algorithm";
681                 goto failure;
682             }
683             alg = (const char *)p;
684             p += alglen;
685
686             key = snew(struct ssh2_userkey);
687             key->alg = find_pubkey_alg_len(alglen, alg);
688             if (!key->alg) {
689                 sfree(key);
690                 fail_reason = "algorithm unknown";
691                 goto failure;
692             }
693
694             bloblen = msgend - p;
695             key->data = key->alg->openssh_createkey(&p, &bloblen);
696             if (!key->data) {
697                 sfree(key);
698                 fail_reason = "key setup failed";
699                 goto failure;
700             }
701
702             /*
703              * p has been advanced by openssh_createkey, but
704              * certainly not _beyond_ the end of the buffer.
705              */
706             assert(p <= msgend);
707
708             if (msgend < p+4) {
709                 key->alg->freekey(key->data);
710                 sfree(key);
711                 fail_reason = "request truncated before key comment";
712                 goto failure;
713             }
714             commlen = toint(GET_32BIT(p));
715             p += 4;
716
717             if (commlen < 0 || commlen > msgend - p) {
718                 key->alg->freekey(key->data);
719                 sfree(key);
720                 fail_reason = "request truncated before key comment";
721                 goto failure;
722             }
723             comment = snewn(commlen + 1, char);
724             if (comment) {
725                 memcpy(comment, p, commlen);
726                 comment[commlen] = '\0';
727             }
728             key->comment = comment;
729
730             if (logfn) {
731                 char *fingerprint = key->alg->fingerprint(key->data);
732                 plog(logctx, logfn, "submitted key: %s %s",
733                      fingerprint, key->comment);
734                 sfree(fingerprint);
735             }
736
737             if (add234(ssh2keys, key) == key) {
738                 keylist_update();
739                 PUT_32BIT(ret, 1);
740                 ret[4] = SSH_AGENT_SUCCESS;
741
742                 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
743             } else {
744                 key->alg->freekey(key->data);
745                 sfree(key->comment);
746                 sfree(key);
747
748                 fail_reason = "key already present";
749                 goto failure;
750             }
751         }
752         break;
753       case SSH1_AGENTC_REMOVE_RSA_IDENTITY:
754         /*
755          * Remove from the list and return SSH_AGENT_SUCCESS, or
756          * perhaps SSH_AGENT_FAILURE if it wasn't in the list to
757          * start with.
758          */
759         {
760             struct RSAKey reqkey, *key;
761             int n;
762
763             plog(logctx, logfn, "request: SSH1_AGENTC_REMOVE_RSA_IDENTITY");
764
765             n = makekey(p, msgend - p, &reqkey, NULL, 0);
766             if (n < 0) {
767                 fail_reason = "request truncated before public key";
768                 goto failure;
769             }
770
771             if (logfn) {
772                 char fingerprint[128];
773                 reqkey.comment = NULL;
774                 rsa_fingerprint(fingerprint, sizeof(fingerprint), &reqkey);
775                 plog(logctx, logfn, "unwanted key: %s", fingerprint);
776             }
777
778             key = find234(rsakeys, &reqkey, NULL);
779             freebn(reqkey.exponent);
780             freebn(reqkey.modulus);
781             PUT_32BIT(ret, 1);
782             if (key) {
783                 plog(logctx, logfn, "found with comment: %s", key->comment);
784
785                 del234(rsakeys, key);
786                 keylist_update();
787                 freersakey(key);
788                 sfree(key);
789                 ret[4] = SSH_AGENT_SUCCESS;
790
791                 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
792             } else {
793                 fail_reason = "key not found";
794                 goto failure;
795             }
796         }
797         break;
798       case SSH2_AGENTC_REMOVE_IDENTITY:
799         /*
800          * Remove from the list and return SSH_AGENT_SUCCESS, or
801          * perhaps SSH_AGENT_FAILURE if it wasn't in the list to
802          * start with.
803          */
804         {
805             struct ssh2_userkey *key;
806             struct blob b;
807
808             plog(logctx, logfn, "request: SSH2_AGENTC_REMOVE_IDENTITY");
809
810             if (msgend < p+4) {
811                 fail_reason = "request truncated before public key";
812                 goto failure;
813             }
814             b.len = toint(GET_32BIT(p));
815             p += 4;
816
817             if (b.len < 0 || b.len > msgend - p) {
818                 fail_reason = "request truncated before public key";
819                 goto failure;
820             }
821             b.blob = p;
822             p += b.len;
823
824             if (logfn) {
825                 char *fingerprint = fingerprint_ssh2_blob(b.blob, b.len);
826                 plog(logctx, logfn, "unwanted key: %s", fingerprint);
827                 sfree(fingerprint);
828             }
829
830             key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm);
831             if (!key) {
832                 fail_reason = "key not found";
833                 goto failure;
834             }
835
836             plog(logctx, logfn, "found with comment: %s", key->comment);
837
838             del234(ssh2keys, key);
839             keylist_update();
840             key->alg->freekey(key->data);
841             sfree(key);
842             PUT_32BIT(ret, 1);
843             ret[4] = SSH_AGENT_SUCCESS;
844
845             plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
846         }
847         break;
848       case SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
849         /*
850          * Remove all SSH-1 keys. Always returns success.
851          */
852         {
853             struct RSAKey *rkey;
854
855             plog(logctx, logfn, "request:"
856                 " SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES");
857
858             while ((rkey = index234(rsakeys, 0)) != NULL) {
859                 del234(rsakeys, rkey);
860                 freersakey(rkey);
861                 sfree(rkey);
862             }
863             keylist_update();
864
865             PUT_32BIT(ret, 1);
866             ret[4] = SSH_AGENT_SUCCESS;
867
868             plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
869         }
870         break;
871       case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
872         /*
873          * Remove all SSH-2 keys. Always returns success.
874          */
875         {
876             struct ssh2_userkey *skey;
877
878             plog(logctx, logfn, "request: SSH2_AGENTC_REMOVE_ALL_IDENTITIES");
879
880             while ((skey = index234(ssh2keys, 0)) != NULL) {
881                 del234(ssh2keys, skey);
882                 skey->alg->freekey(skey->data);
883                 sfree(skey);
884             }
885             keylist_update();
886
887             PUT_32BIT(ret, 1);
888             ret[4] = SSH_AGENT_SUCCESS;
889
890             plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
891         }
892         break;
893       default:
894         plog(logctx, logfn, "request: unknown message type %d", type);
895
896         fail_reason = "unrecognised message";
897         /* fall through */
898       failure:
899         /*
900          * Unrecognised message. Return SSH_AGENT_FAILURE.
901          */
902         PUT_32BIT(ret, 1);
903         ret[4] = SSH_AGENT_FAILURE;
904         plog(logctx, logfn, "reply: SSH_AGENT_FAILURE (%s)", fail_reason);
905         break;
906     }
907
908     *outlen = 4 + GET_32BIT(ret);
909     return ret;
910 }
911
912 void *pageant_failure_msg(int *outlen)
913 {
914     unsigned char *ret = snewn(5, unsigned char);
915     PUT_32BIT(ret, 1);
916     ret[4] = SSH_AGENT_FAILURE;
917     *outlen = 5;
918     return ret;
919 }
920
921 void pageant_init(void)
922 {
923     pageant_local = TRUE;
924     rsakeys = newtree234(cmpkeys_rsa);
925     ssh2keys = newtree234(cmpkeys_ssh2);
926 }
927
928 struct RSAKey *pageant_nth_ssh1_key(int i)
929 {
930     return index234(rsakeys, i);
931 }
932
933 struct ssh2_userkey *pageant_nth_ssh2_key(int i)
934 {
935     return index234(ssh2keys, i);
936 }
937
938 int pageant_count_ssh1_keys(void)
939 {
940     return count234(rsakeys);
941 }
942
943 int pageant_count_ssh2_keys(void)
944 {
945     return count234(ssh2keys);
946 }
947
948 int pageant_add_ssh1_key(struct RSAKey *rkey)
949 {
950     return add234(rsakeys, rkey) == rkey;
951 }
952
953 int pageant_add_ssh2_key(struct ssh2_userkey *skey)
954 {
955     return add234(ssh2keys, skey) == skey;
956 }
957
958 int pageant_delete_ssh1_key(struct RSAKey *rkey)
959 {
960     struct RSAKey *deleted = del234(rsakeys, rkey);
961     if (!deleted)
962         return FALSE;
963     assert(deleted == rkey);
964     return TRUE;
965 }
966
967 int pageant_delete_ssh2_key(struct ssh2_userkey *skey)
968 {
969     struct ssh2_userkey *deleted = del234(ssh2keys, skey);
970     if (!deleted)
971         return FALSE;
972     assert(deleted == skey);
973     return TRUE;
974 }
975
976 /* ----------------------------------------------------------------------
977  * The agent plug.
978  */
979
980 /*
981  * Coroutine macros similar to, but simplified from, those in ssh.c.
982  */
983 #define crBegin(v)      { int *crLine = &v; switch(v) { case 0:;
984 #define crFinish(z)     } *crLine = 0; return (z); }
985 #define crGetChar(c) do                                         \
986     {                                                           \
987         while (len == 0) {                                      \
988             *crLine =__LINE__; return 1; case __LINE__:;        \
989         }                                                       \
990         len--;                                                  \
991         (c) = (unsigned char)*data++;                           \
992     } while (0)
993
994 struct pageant_conn_state {
995     const struct plug_function_table *fn;
996     /* the above variable absolutely *must* be the first in this structure */
997
998     Socket connsock;
999     void *logctx;
1000     pageant_logfn_t logfn;
1001     unsigned char lenbuf[4], pktbuf[AGENT_MAX_MSGLEN];
1002     unsigned len, got;
1003     int real_packet;
1004     int crLine;            /* for coroutine in pageant_conn_receive */
1005 };
1006
1007 static int pageant_conn_closing(Plug plug, const char *error_msg,
1008                                 int error_code, int calling_back)
1009 {
1010     struct pageant_conn_state *pc = (struct pageant_conn_state *)plug;
1011     if (error_msg)
1012         plog(pc->logctx, pc->logfn, "%p: error: %s", pc, error_msg);
1013     else
1014         plog(pc->logctx, pc->logfn, "%p: connection closed", pc);
1015     sk_close(pc->connsock);
1016     sfree(pc);
1017     return 1;
1018 }
1019
1020 static void pageant_conn_sent(Plug plug, int bufsize)
1021 {
1022     /* struct pageant_conn_state *pc = (struct pageant_conn_state *)plug; */
1023
1024     /*
1025      * We do nothing here, because we expect that there won't be a
1026      * need to throttle and unthrottle the connection to an agent -
1027      * clients will typically not send many requests, and will wait
1028      * until they receive each reply before sending a new request.
1029      */
1030 }
1031
1032 static void pageant_conn_log(void *logctx, const char *fmt, va_list ap)
1033 {
1034     /* Wrapper on pc->logfn that prefixes the connection identifier */
1035     struct pageant_conn_state *pc = (struct pageant_conn_state *)logctx;
1036     char *formatted = dupvprintf(fmt, ap);
1037     plog(pc->logctx, pc->logfn, "%p: %s", pc, formatted);
1038     sfree(formatted);
1039 }
1040
1041 static int pageant_conn_receive(Plug plug, int urgent, char *data, int len)
1042 {
1043     struct pageant_conn_state *pc = (struct pageant_conn_state *)plug;
1044     char c;
1045
1046     crBegin(pc->crLine);
1047
1048     while (len > 0) {
1049         pc->got = 0;
1050         while (pc->got < 4) {
1051             crGetChar(c);
1052             pc->lenbuf[pc->got++] = c;
1053         }
1054
1055         pc->len = GET_32BIT(pc->lenbuf);
1056         pc->got = 0;
1057         pc->real_packet = (pc->len < AGENT_MAX_MSGLEN-4);
1058
1059         while (pc->got < pc->len) {
1060             crGetChar(c);
1061             if (pc->real_packet)
1062                 pc->pktbuf[pc->got] = c;
1063             pc->got++;
1064         }
1065
1066         {
1067             void *reply;
1068             int replylen;
1069
1070             if (pc->real_packet) {
1071                 reply = pageant_handle_msg(pc->pktbuf, pc->len, &replylen, pc,
1072                                            pc->logfn?pageant_conn_log:NULL);
1073             } else {
1074                 plog(pc->logctx, pc->logfn, "%p: overlong message (%u)",
1075                      pc, pc->len);
1076                 plog(pc->logctx, pc->logfn, "%p: reply: SSH_AGENT_FAILURE "
1077                      "(message too long)", pc);
1078                 reply = pageant_failure_msg(&replylen);
1079             }
1080             sk_write(pc->connsock, reply, replylen);
1081             smemclr(reply, replylen);
1082         }
1083     }
1084
1085     crFinish(1);
1086 }
1087
1088 struct pageant_listen_state {
1089     const struct plug_function_table *fn;
1090     /* the above variable absolutely *must* be the first in this structure */
1091
1092     Socket listensock;
1093     void *logctx;
1094     pageant_logfn_t logfn;
1095 };
1096
1097 static int pageant_listen_closing(Plug plug, const char *error_msg,
1098                                   int error_code, int calling_back)
1099 {
1100     struct pageant_listen_state *pl = (struct pageant_listen_state *)plug;
1101     if (error_msg)
1102         plog(pl->logctx, pl->logfn, "listening socket: error: %s", error_msg);
1103     sk_close(pl->listensock);
1104     pl->listensock = NULL;
1105     return 1;
1106 }
1107
1108 static int pageant_listen_accepting(Plug plug,
1109                                     accept_fn_t constructor, accept_ctx_t ctx)
1110 {
1111     static const struct plug_function_table connection_fn_table = {
1112         NULL, /* no log function, because that's for outgoing connections */
1113         pageant_conn_closing,
1114         pageant_conn_receive,
1115         pageant_conn_sent,
1116         NULL /* no accepting function, because we've already done it */
1117     };
1118     struct pageant_listen_state *pl = (struct pageant_listen_state *)plug;
1119     struct pageant_conn_state *pc;
1120     const char *err;
1121
1122     pc = snew(struct pageant_conn_state);
1123     pc->fn = &connection_fn_table;
1124     pc->logfn = pl->logfn;
1125     pc->logctx = pl->logctx;
1126     pc->crLine = 0;
1127
1128     pc->connsock = constructor(ctx, (Plug) pc);
1129     if ((err = sk_socket_error(pc->connsock)) != NULL) {
1130         sk_close(pc->connsock);
1131         sfree(pc);
1132         return TRUE;
1133     }
1134
1135     sk_set_frozen(pc->connsock, 0);
1136
1137     /* FIXME: can we get any useful peer id info? */
1138     plog(pl->logctx, pl->logfn, "%p: new connection", pc);
1139
1140     return 0;
1141 }
1142
1143 struct pageant_listen_state *pageant_listener_new(void)
1144 {
1145     static const struct plug_function_table listener_fn_table = {
1146         NULL, /* no log function, because that's for outgoing connections */
1147         pageant_listen_closing,
1148         NULL, /* no receive function on a listening socket */
1149         NULL, /* no sent function on a listening socket */
1150         pageant_listen_accepting
1151     };
1152
1153     struct pageant_listen_state *pl = snew(struct pageant_listen_state);
1154     pl->fn = &listener_fn_table;
1155     pl->logctx = NULL;
1156     pl->logfn = NULL;
1157     pl->listensock = NULL;
1158     return pl;
1159 }
1160
1161 void pageant_listener_got_socket(struct pageant_listen_state *pl, Socket sock)
1162 {
1163     pl->listensock = sock;
1164 }
1165
1166 void pageant_listener_set_logfn(struct pageant_listen_state *pl,
1167                                 void *logctx, pageant_logfn_t logfn)
1168 {
1169     pl->logctx = logctx;
1170     pl->logfn = logfn;
1171 }
1172
1173 void pageant_listener_free(struct pageant_listen_state *pl)
1174 {
1175     if (pl->listensock)
1176         sk_close(pl->listensock);
1177     sfree(pl);
1178 }
1179
1180 /* ----------------------------------------------------------------------
1181  * Code to perform agent operations either as a client, or within the
1182  * same process as the running agent.
1183  */
1184
1185 static tree234 *passphrases = NULL;
1186
1187 /*
1188  * After processing a list of filenames, we want to forget the
1189  * passphrases.
1190  */
1191 void pageant_forget_passphrases(void)
1192 {
1193     while (count234(passphrases) > 0) {
1194         char *pp = index234(passphrases, 0);
1195         smemclr(pp, strlen(pp));
1196         delpos234(passphrases, 0);
1197         free(pp);
1198     }
1199 }
1200
1201 void *pageant_get_keylist1(int *length)
1202 {
1203     void *ret;
1204
1205     if (!pageant_local) {
1206         unsigned char request[5], *response;
1207         void *vresponse;
1208         int resplen, retval;
1209         request[4] = SSH1_AGENTC_REQUEST_RSA_IDENTITIES;
1210         PUT_32BIT(request, 4);
1211
1212         retval = agent_query(request, 5, &vresponse, &resplen, NULL, NULL);
1213         assert(retval == 1);
1214         response = vresponse;
1215         if (resplen < 5 || response[4] != SSH1_AGENT_RSA_IDENTITIES_ANSWER) {
1216             sfree(response);
1217             return NULL;
1218         }
1219
1220         ret = snewn(resplen-5, unsigned char);
1221         memcpy(ret, response+5, resplen-5);
1222         sfree(response);
1223
1224         if (length)
1225             *length = resplen-5;
1226     } else {
1227         ret = pageant_make_keylist1(length);
1228     }
1229     return ret;
1230 }
1231
1232 void *pageant_get_keylist2(int *length)
1233 {
1234     void *ret;
1235
1236     if (!pageant_local) {
1237         unsigned char request[5], *response;
1238         void *vresponse;
1239         int resplen, retval;
1240
1241         request[4] = SSH2_AGENTC_REQUEST_IDENTITIES;
1242         PUT_32BIT(request, 4);
1243
1244         retval = agent_query(request, 5, &vresponse, &resplen, NULL, NULL);
1245         assert(retval == 1);
1246         response = vresponse;
1247         if (resplen < 5 || response[4] != SSH2_AGENT_IDENTITIES_ANSWER) {
1248             sfree(response);
1249             return NULL;
1250         }
1251
1252         ret = snewn(resplen-5, unsigned char);
1253         memcpy(ret, response+5, resplen-5);
1254         sfree(response);
1255
1256         if (length)
1257             *length = resplen-5;
1258     } else {
1259         ret = pageant_make_keylist2(length);
1260     }
1261     return ret;
1262 }
1263
1264 int pageant_add_keyfile(Filename *filename, const char *passphrase,
1265                         char **retstr)
1266 {
1267     struct RSAKey *rkey = NULL;
1268     struct ssh2_userkey *skey = NULL;
1269     int needs_pass;
1270     int ret;
1271     int attempts;
1272     char *comment;
1273     const char *this_passphrase;
1274     const char *error = NULL;
1275     int type;
1276
1277     if (!passphrases) {
1278         passphrases = newtree234(NULL);
1279     }
1280
1281     *retstr = NULL;
1282
1283     type = key_type(filename);
1284     if (type != SSH_KEYTYPE_SSH1 && type != SSH_KEYTYPE_SSH2) {
1285         *retstr = dupprintf("Couldn't load this key (%s)",
1286                             key_type_to_str(type));
1287         return PAGEANT_ACTION_FAILURE;
1288     }
1289
1290     /*
1291      * See if the key is already loaded (in the primary Pageant,
1292      * which may or may not be us).
1293      */
1294     {
1295         void *blob;
1296         unsigned char *keylist, *p;
1297         int i, nkeys, bloblen, keylistlen;
1298
1299         if (type == SSH_KEYTYPE_SSH1) {
1300             if (!rsakey_pubblob(filename, &blob, &bloblen, NULL, &error)) {
1301                 *retstr = dupprintf("Couldn't load private key (%s)", error);
1302                 return PAGEANT_ACTION_FAILURE;
1303             }
1304             keylist = pageant_get_keylist1(&keylistlen);
1305         } else {
1306             unsigned char *blob2;
1307             blob = ssh2_userkey_loadpub(filename, NULL, &bloblen,
1308                                         NULL, &error);
1309             if (!blob) {
1310                 *retstr = dupprintf("Couldn't load private key (%s)", error);
1311                 return PAGEANT_ACTION_FAILURE;
1312             }
1313             /* For our purposes we want the blob prefixed with its length */
1314             blob2 = snewn(bloblen+4, unsigned char);
1315             PUT_32BIT(blob2, bloblen);
1316             memcpy(blob2 + 4, blob, bloblen);
1317             sfree(blob);
1318             blob = blob2;
1319
1320             keylist = pageant_get_keylist2(&keylistlen);
1321         }
1322         if (keylist) {
1323             if (keylistlen < 4) {
1324                 *retstr = dupstr("Received broken key list from agent");
1325                 return PAGEANT_ACTION_FAILURE;
1326             }
1327             nkeys = toint(GET_32BIT(keylist));
1328             if (nkeys < 0) {
1329                 *retstr = dupstr("Received broken key list from agent");
1330                 return PAGEANT_ACTION_FAILURE;
1331             }
1332             p = keylist + 4;
1333             keylistlen -= 4;
1334
1335             for (i = 0; i < nkeys; i++) {
1336                 if (!memcmp(blob, p, bloblen)) {
1337                     /* Key is already present; we can now leave. */
1338                     sfree(keylist);
1339                     sfree(blob);
1340                     return PAGEANT_ACTION_OK;
1341                 }
1342                 /* Now skip over public blob */
1343                 if (type == SSH_KEYTYPE_SSH1) {
1344                     int n = rsa_public_blob_len(p, keylistlen);
1345                     if (n < 0) {
1346                         *retstr = dupstr("Received broken key list from agent");
1347                         return PAGEANT_ACTION_FAILURE;
1348                     }
1349                     p += n;
1350                     keylistlen -= n;
1351                 } else {
1352                     int n;
1353                     if (keylistlen < 4) {
1354                         *retstr = dupstr("Received broken key list from agent");
1355                         return PAGEANT_ACTION_FAILURE;
1356                     }
1357                     n = toint(4 + GET_32BIT(p));
1358                     if (n < 0 || keylistlen < n) {
1359                         *retstr = dupstr("Received broken key list from agent");
1360                         return PAGEANT_ACTION_FAILURE;
1361                     }
1362                     p += n;
1363                     keylistlen -= n;
1364                 }
1365                 /* Now skip over comment field */
1366                 {
1367                     int n;
1368                     if (keylistlen < 4) {
1369                         *retstr = dupstr("Received broken key list from agent");
1370                         return PAGEANT_ACTION_FAILURE;
1371                     }
1372                     n = toint(4 + GET_32BIT(p));
1373                     if (n < 0 || keylistlen < n) {
1374                         *retstr = dupstr("Received broken key list from agent");
1375                         return PAGEANT_ACTION_FAILURE;
1376                     }
1377                     p += n;
1378                     keylistlen -= n;
1379                 }
1380             }
1381
1382             sfree(keylist);
1383         }
1384
1385         sfree(blob);
1386     }
1387
1388     error = NULL;
1389     if (type == SSH_KEYTYPE_SSH1)
1390         needs_pass = rsakey_encrypted(filename, &comment);
1391     else
1392         needs_pass = ssh2_userkey_encrypted(filename, &comment);
1393     attempts = 0;
1394     if (type == SSH_KEYTYPE_SSH1)
1395         rkey = snew(struct RSAKey);
1396
1397     /*
1398      * Loop round repeatedly trying to load the key, until we either
1399      * succeed, fail for some serious reason, or run out of
1400      * passphrases to try.
1401      */
1402     while (1) {
1403         if (needs_pass) {
1404
1405             /*
1406              * If we've been given a passphrase on input, try using
1407              * it. Otherwise, try one from our tree234 of previously
1408              * useful passphrases.
1409              */
1410             if (passphrase) {
1411                 this_passphrase = (attempts == 0 ? passphrase : NULL);
1412             } else {
1413                 this_passphrase = (const char *)index234(passphrases, attempts);
1414             }
1415
1416             if (!this_passphrase) {
1417                 /*
1418                  * Run out of passphrases to try.
1419                  */
1420                 *retstr = comment;
1421                 return PAGEANT_ACTION_NEED_PP;
1422             }
1423         } else
1424             this_passphrase = "";
1425
1426         if (type == SSH_KEYTYPE_SSH1)
1427             ret = loadrsakey(filename, rkey, this_passphrase, &error);
1428         else {
1429             skey = ssh2_load_userkey(filename, this_passphrase, &error);
1430             if (skey == SSH2_WRONG_PASSPHRASE)
1431                 ret = -1;
1432             else if (!skey)
1433                 ret = 0;
1434             else
1435                 ret = 1;
1436         }
1437
1438         if (ret == 0) {
1439             /*
1440              * Failed to load the key file, for some reason other than
1441              * a bad passphrase.
1442              */
1443             *retstr = dupstr(error);
1444             return PAGEANT_ACTION_FAILURE;
1445         } else if (ret == 1) {
1446             /*
1447              * Successfully loaded the key file.
1448              */
1449             break;
1450         } else {
1451             /*
1452              * Passphrase wasn't right; go round again.
1453              */
1454             attempts++;
1455         }
1456     }
1457
1458     /*
1459      * If we get here, we've succesfully loaded the key into
1460      * rkey/skey, but not yet added it to the agent.
1461      */
1462
1463     /*
1464      * If the key was successfully decrypted, save the passphrase for
1465      * use with other keys we try to load.
1466      */
1467     {
1468         char *pp_copy = dupstr(this_passphrase);
1469         if (addpos234(passphrases, pp_copy, 0) != pp_copy) {
1470             /* No need; it was already there. */
1471             smemclr(pp_copy, strlen(pp_copy));
1472             sfree(pp_copy);
1473         }
1474     }
1475
1476     if (comment)
1477         sfree(comment);
1478
1479     if (type == SSH_KEYTYPE_SSH1) {
1480         if (!pageant_local) {
1481             unsigned char *request, *response;
1482             void *vresponse;
1483             int reqlen, clen, resplen, ret;
1484
1485             clen = strlen(rkey->comment);
1486
1487             reqlen = 4 + 1 +           /* length, message type */
1488                 4 +                    /* bit count */
1489                 ssh1_bignum_length(rkey->modulus) +
1490                 ssh1_bignum_length(rkey->exponent) +
1491                 ssh1_bignum_length(rkey->private_exponent) +
1492                 ssh1_bignum_length(rkey->iqmp) +
1493                 ssh1_bignum_length(rkey->p) +
1494                 ssh1_bignum_length(rkey->q) + 4 + clen  /* comment */
1495                 ;
1496
1497             request = snewn(reqlen, unsigned char);
1498
1499             request[4] = SSH1_AGENTC_ADD_RSA_IDENTITY;
1500             reqlen = 5;
1501             PUT_32BIT(request + reqlen, bignum_bitcount(rkey->modulus));
1502             reqlen += 4;
1503             reqlen += ssh1_write_bignum(request + reqlen, rkey->modulus);
1504             reqlen += ssh1_write_bignum(request + reqlen, rkey->exponent);
1505             reqlen +=
1506                 ssh1_write_bignum(request + reqlen,
1507                                   rkey->private_exponent);
1508             reqlen += ssh1_write_bignum(request + reqlen, rkey->iqmp);
1509             reqlen += ssh1_write_bignum(request + reqlen, rkey->p);
1510             reqlen += ssh1_write_bignum(request + reqlen, rkey->q);
1511             PUT_32BIT(request + reqlen, clen);
1512             memcpy(request + reqlen + 4, rkey->comment, clen);
1513             reqlen += 4 + clen;
1514             PUT_32BIT(request, reqlen - 4);
1515
1516             ret = agent_query(request, reqlen, &vresponse, &resplen,
1517                               NULL, NULL);
1518             assert(ret == 1);
1519             response = vresponse;
1520             if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
1521                 *retstr = dupstr("The already running Pageant "
1522                                  "refused to add the key.");
1523                 return PAGEANT_ACTION_FAILURE;
1524             }
1525             sfree(request);
1526             sfree(response);
1527         } else {
1528             if (!pageant_add_ssh1_key(rkey)) {
1529                 sfree(rkey);           /* already present, don't waste RAM */
1530             }
1531         }
1532     } else {
1533         if (!pageant_local) {
1534             unsigned char *request, *response;
1535             void *vresponse;
1536             int reqlen, alglen, clen, keybloblen, resplen, ret;
1537             alglen = strlen(skey->alg->name);
1538             clen = strlen(skey->comment);
1539
1540             keybloblen = skey->alg->openssh_fmtkey(skey->data, NULL, 0);
1541
1542             reqlen = 4 + 1 +           /* length, message type */
1543                 4 + alglen +           /* algorithm name */
1544                 keybloblen +           /* key data */
1545                 4 + clen               /* comment */
1546                 ;
1547
1548             request = snewn(reqlen, unsigned char);
1549
1550             request[4] = SSH2_AGENTC_ADD_IDENTITY;
1551             reqlen = 5;
1552             PUT_32BIT(request + reqlen, alglen);
1553             reqlen += 4;
1554             memcpy(request + reqlen, skey->alg->name, alglen);
1555             reqlen += alglen;
1556             reqlen += skey->alg->openssh_fmtkey(skey->data,
1557                                                 request + reqlen,
1558                                                 keybloblen);
1559             PUT_32BIT(request + reqlen, clen);
1560             memcpy(request + reqlen + 4, skey->comment, clen);
1561             reqlen += clen + 4;
1562             PUT_32BIT(request, reqlen - 4);
1563
1564             ret = agent_query(request, reqlen, &vresponse, &resplen,
1565                               NULL, NULL);
1566             assert(ret == 1);
1567             response = vresponse;
1568             if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
1569                 *retstr = dupstr("The already running Pageant "
1570                                  "refused to add the key.");
1571                 return PAGEANT_ACTION_FAILURE;
1572             }
1573
1574             sfree(request);
1575             sfree(response);
1576         } else {
1577             if (!pageant_add_ssh2_key(skey)) {
1578                 skey->alg->freekey(skey->data);
1579                 sfree(skey);           /* already present, don't waste RAM */
1580             }
1581         }
1582     }
1583     return PAGEANT_ACTION_OK;
1584 }