2 * pageant.c: cross-platform code to implement Pageant.
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
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.
25 modalfatalbox("Internal error: attempt to use random numbers in Pageant");
27 return 0; /* unreachable, but placate optimiser */
30 static int pageant_local = FALSE;
33 * rsakeys stores SSH-1 RSA keys. ssh2keys stores all SSH-2 keys.
35 static tree234 *rsakeys, *ssh2keys;
38 * Blob structure for passing to the asymmetric SSH-2 key compare
39 * function, prototyped here.
42 const unsigned char *blob;
45 static int cmpkeys_ssh2_asymm(void *av, void *bv);
48 * Key comparison function for the 2-3-4 tree of RSA keys.
50 static int cmpkeys_rsa(void *av, void *bv)
52 struct RSAKey *a = (struct RSAKey *) av;
53 struct RSAKey *b = (struct RSAKey *) bv;
60 * Compare by length of moduli.
62 alen = bignum_bitcount(am);
63 blen = bignum_bitcount(bm);
69 * Now compare by moduli themselves.
71 alen = (alen + 7) / 8; /* byte count */
74 abyte = bignum_byte(am, alen);
75 bbyte = bignum_byte(bm, alen);
78 else if (abyte < bbyte)
88 * Key comparison function for the 2-3-4 tree of SSH-2 keys.
90 static int cmpkeys_ssh2(void *av, void *bv)
92 struct ssh2_userkey *a = (struct ssh2_userkey *) av;
93 struct ssh2_userkey *b = (struct ssh2_userkey *) bv;
96 unsigned char *ablob, *bblob;
100 * Compare purely by public blob.
102 ablob = a->alg->public_blob(a->data, &alen);
103 bblob = b->alg->public_blob(b->data, &blen);
106 for (i = 0; i < alen && i < blen; i++) {
107 if (ablob[i] < bblob[i]) {
110 } else if (ablob[i] > bblob[i]) {
115 if (c == 0 && i < alen)
116 c = +1; /* a is longer */
117 if (c == 0 && i < blen)
118 c = -1; /* a is longer */
127 * Key comparison function for looking up a blob in the 2-3-4 tree
130 static int cmpkeys_ssh2_asymm(void *av, void *bv)
132 struct blob *a = (struct blob *) av;
133 struct ssh2_userkey *b = (struct ssh2_userkey *) bv;
136 const unsigned char *ablob;
137 unsigned char *bblob;
141 * Compare purely by public blob.
145 bblob = b->alg->public_blob(b->data, &blen);
148 for (i = 0; i < alen && i < blen; i++) {
149 if (ablob[i] < bblob[i]) {
152 } else if (ablob[i] > bblob[i]) {
157 if (c == 0 && i < alen)
158 c = +1; /* a is longer */
159 if (c == 0 && i < blen)
160 c = -1; /* a is longer */
168 * Create an SSH-1 key list in a malloc'ed buffer; return its
171 void *pageant_make_keylist1(int *length)
175 unsigned char *blob, *p, *ret;
179 * Count up the number and length of keys we hold.
183 for (i = 0; NULL != (key = index234(rsakeys, i)); i++) {
185 blob = rsa_public_blob(key, &bloblen);
188 len += 4 + strlen(key->comment);
191 /* Allocate the buffer. */
192 p = ret = snewn(len, unsigned char);
193 if (length) *length = len;
197 for (i = 0; NULL != (key = index234(rsakeys, i)); i++) {
198 blob = rsa_public_blob(key, &bloblen);
199 memcpy(p, blob, bloblen);
202 PUT_32BIT(p, strlen(key->comment));
203 memcpy(p + 4, key->comment, strlen(key->comment));
204 p += 4 + strlen(key->comment);
207 assert(p - ret == len);
212 * Create an SSH-2 key list in a malloc'ed buffer; return its
215 void *pageant_make_keylist2(int *length)
217 struct ssh2_userkey *key;
219 unsigned char *blob, *p, *ret;
223 * Count up the number and length of keys we hold.
227 for (i = 0; NULL != (key = index234(ssh2keys, i)); i++) {
229 len += 4; /* length field */
230 blob = key->alg->public_blob(key->data, &bloblen);
233 len += 4 + strlen(key->comment);
236 /* Allocate the buffer. */
237 p = ret = snewn(len, unsigned char);
238 if (length) *length = len;
241 * Packet header is the obvious five bytes, plus four
242 * bytes for the key count.
246 for (i = 0; NULL != (key = index234(ssh2keys, i)); i++) {
247 blob = key->alg->public_blob(key->data, &bloblen);
248 PUT_32BIT(p, bloblen);
250 memcpy(p, blob, bloblen);
253 PUT_32BIT(p, strlen(key->comment));
254 memcpy(p + 4, key->comment, strlen(key->comment));
255 p += 4 + strlen(key->comment);
258 assert(p - ret == len);
262 static void plog(void *logctx, pageant_logfn_t logfn, const char *fmt, ...)
264 __attribute__ ((format (printf, 3, 4)))
268 static void plog(void *logctx, pageant_logfn_t logfn, const char *fmt, ...)
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.
281 logfn(logctx, fmt, ap);
286 void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
287 void *logctx, pageant_logfn_t logfn)
289 const unsigned char *p = msg;
290 const unsigned char *msgend;
291 unsigned char *ret = snewn(AGENT_MAX_MSGLEN, unsigned char);
293 const char *fail_reason;
298 * Get the message type.
301 fail_reason = "message contained no type code";
307 case SSH1_AGENTC_REQUEST_RSA_IDENTITIES:
309 * Reply with SSH1_AGENT_RSA_IDENTITIES_ANSWER.
315 plog(logctx, logfn, "request: SSH1_AGENTC_REQUEST_RSA_IDENTITIES");
317 ret[4] = SSH1_AGENT_RSA_IDENTITIES_ANSWER;
318 keylist = pageant_make_keylist1(&len);
319 if (len + 5 > AGENT_MAX_MSGLEN) {
321 fail_reason = "output would exceed max msglen";
324 PUT_32BIT(ret, len + 1);
325 memcpy(ret + 5, keylist, len);
327 plog(logctx, logfn, "reply: SSH1_AGENT_RSA_IDENTITIES_ANSWER");
328 if (logfn) { /* skip this loop if not logging */
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);
340 case SSH2_AGENTC_REQUEST_IDENTITIES:
342 * Reply with SSH2_AGENT_IDENTITIES_ANSWER.
348 plog(logctx, logfn, "request: SSH2_AGENTC_REQUEST_IDENTITIES");
350 ret[4] = SSH2_AGENT_IDENTITIES_ANSWER;
351 keylist = pageant_make_keylist2(&len);
352 if (len + 5 > AGENT_MAX_MSGLEN) {
354 fail_reason = "output would exceed max msglen";
357 PUT_32BIT(ret, len + 1);
358 memcpy(ret + 5, keylist, len);
360 plog(logctx, logfn, "reply: SSH2_AGENT_IDENTITIES_ANSWER");
361 if (logfn) { /* skip this loop if not logging */
363 struct ssh2_userkey *skey;
364 for (i = 0; NULL != (skey = pageant_nth_ssh2_key(i)); i++) {
365 char *fingerprint = ssh2_fingerprint(skey->alg,
367 plog(logctx, logfn, "returned key: %s %s",
368 fingerprint, skey->comment);
376 case SSH1_AGENTC_RSA_CHALLENGE:
378 * Reply with either SSH1_AGENT_RSA_RESPONSE or
379 * SSH_AGENT_FAILURE, depending on whether we have that key
383 struct RSAKey reqkey, *key;
384 Bignum challenge, response;
385 unsigned char response_source[48], response_md5[16];
386 struct MD5Context md5c;
389 plog(logctx, logfn, "request: SSH1_AGENTC_RSA_CHALLENGE");
392 i = ssh1_read_bignum(p, msgend - p, &reqkey.exponent);
394 fail_reason = "request truncated before key exponent";
398 i = ssh1_read_bignum(p, msgend - p, &reqkey.modulus);
400 freebn(reqkey.exponent);
401 fail_reason = "request truncated before key modulus";
405 i = ssh1_read_bignum(p, msgend - p, &challenge);
407 freebn(reqkey.exponent);
408 freebn(reqkey.modulus);
410 fail_reason = "request truncated before challenge";
415 freebn(reqkey.exponent);
416 freebn(reqkey.modulus);
418 fail_reason = "request truncated before session id";
421 memcpy(response_source + 32, p, 16);
424 freebn(reqkey.exponent);
425 freebn(reqkey.modulus);
427 fail_reason = "request truncated before response type";
430 if (GET_32BIT(p) != 1) {
431 freebn(reqkey.exponent);
432 freebn(reqkey.modulus);
434 fail_reason = "response type other than 1 not supported";
438 char fingerprint[128];
439 reqkey.comment = NULL;
440 rsa_fingerprint(fingerprint, sizeof(fingerprint), &reqkey);
441 plog(logctx, logfn, "requested key: %s", fingerprint);
443 if ((key = find234(rsakeys, &reqkey, NULL)) == NULL) {
444 freebn(reqkey.exponent);
445 freebn(reqkey.modulus);
447 fail_reason = "key not found";
450 response = rsadecrypt(challenge, key);
451 for (i = 0; i < 32; i++)
452 response_source[i] = bignum_byte(response, 31 - i);
455 MD5Update(&md5c, response_source, 48);
456 MD5Final(response_md5, &md5c);
457 smemclr(response_source, 48); /* burn the evidence */
458 freebn(response); /* and that evidence */
459 freebn(challenge); /* yes, and that evidence */
460 freebn(reqkey.exponent); /* and free some memory ... */
461 freebn(reqkey.modulus); /* ... while we're at it. */
464 * Packet is the obvious five byte header, plus sixteen
468 PUT_32BIT(ret, len - 4);
469 ret[4] = SSH1_AGENT_RSA_RESPONSE;
470 memcpy(ret + 5, response_md5, 16);
472 plog(logctx, logfn, "reply: SSH1_AGENT_RSA_RESPONSE");
475 case SSH2_AGENTC_SIGN_REQUEST:
477 * Reply with either SSH2_AGENT_SIGN_RESPONSE or
478 * SSH_AGENT_FAILURE, depending on whether we have that key
482 struct ssh2_userkey *key;
484 const unsigned char *data;
485 unsigned char *signature;
486 int datalen, siglen, len;
488 plog(logctx, logfn, "request: SSH2_AGENTC_SIGN_REQUEST");
491 fail_reason = "request truncated before public key";
494 b.len = toint(GET_32BIT(p));
495 if (b.len < 0 || b.len > msgend - (p+4)) {
496 fail_reason = "request truncated before public key";
503 fail_reason = "request truncated before string to sign";
506 datalen = toint(GET_32BIT(p));
508 if (datalen < 0 || datalen > msgend - p) {
509 fail_reason = "request truncated before string to sign";
514 char *fingerprint = ssh2_fingerprint_blob(b.blob, b.len);
515 plog(logctx, logfn, "requested key: %s", fingerprint);
518 key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm);
520 fail_reason = "key not found";
523 signature = key->alg->sign(key->data, (const char *)data,
525 len = 5 + 4 + siglen;
526 PUT_32BIT(ret, len - 4);
527 ret[4] = SSH2_AGENT_SIGN_RESPONSE;
528 PUT_32BIT(ret + 5, siglen);
529 memcpy(ret + 5 + 4, signature, siglen);
532 plog(logctx, logfn, "reply: SSH2_AGENT_SIGN_RESPONSE");
535 case SSH1_AGENTC_ADD_RSA_IDENTITY:
537 * Add to the list and return SSH_AGENT_SUCCESS, or
538 * SSH_AGENT_FAILURE if the key was malformed.
545 plog(logctx, logfn, "request: SSH1_AGENTC_ADD_RSA_IDENTITY");
547 key = snew(struct RSAKey);
548 memset(key, 0, sizeof(struct RSAKey));
550 n = makekey(p, msgend - p, key, NULL, 1);
554 fail_reason = "request truncated before public key";
559 n = makeprivate(p, msgend - p, key);
563 fail_reason = "request truncated before private key";
568 /* SSH-1 names p and q the other way round, i.e. we have
569 * the inverse of p mod q and not of q mod p. We swap the
570 * names, because our internal RSA wants iqmp. */
572 n = ssh1_read_bignum(p, msgend - p, &key->iqmp); /* p^-1 mod q */
576 fail_reason = "request truncated before iqmp";
581 n = ssh1_read_bignum(p, msgend - p, &key->q); /* p */
585 fail_reason = "request truncated before p";
590 n = ssh1_read_bignum(p, msgend - p, &key->p); /* q */
594 fail_reason = "request truncated before q";
602 fail_reason = "request truncated before key comment";
605 commentlen = toint(GET_32BIT(p));
607 if (commentlen < 0 || commentlen > msgend - p) {
610 fail_reason = "request truncated before key comment";
614 comment = snewn(commentlen+1, char);
616 memcpy(comment, p + 4, commentlen);
617 comment[commentlen] = '\0';
618 key->comment = comment;
622 char fingerprint[128];
623 rsa_fingerprint(fingerprint, sizeof(fingerprint), key);
624 plog(logctx, logfn, "submitted key: %s", fingerprint);
627 if (add234(rsakeys, key) == key) {
630 ret[4] = SSH_AGENT_SUCCESS;
632 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
637 fail_reason = "key already present";
642 case SSH2_AGENTC_ADD_IDENTITY:
644 * Add to the list and return SSH_AGENT_SUCCESS, or
645 * SSH_AGENT_FAILURE if the key was malformed.
648 struct ssh2_userkey *key;
654 plog(logctx, logfn, "request: SSH2_AGENTC_ADD_IDENTITY");
657 fail_reason = "request truncated before key algorithm";
660 alglen = toint(GET_32BIT(p));
662 if (alglen < 0 || alglen > msgend - p) {
663 fail_reason = "request truncated before key algorithm";
666 alg = (const char *)p;
669 key = snew(struct ssh2_userkey);
670 key->alg = find_pubkey_alg_len(alglen, alg);
673 fail_reason = "algorithm unknown";
677 bloblen = msgend - p;
678 key->data = key->alg->openssh_createkey(key->alg, &p, &bloblen);
681 fail_reason = "key setup failed";
686 * p has been advanced by openssh_createkey, but
687 * certainly not _beyond_ the end of the buffer.
692 key->alg->freekey(key->data);
694 fail_reason = "request truncated before key comment";
697 commlen = toint(GET_32BIT(p));
700 if (commlen < 0 || commlen > msgend - p) {
701 key->alg->freekey(key->data);
703 fail_reason = "request truncated before key comment";
706 comment = snewn(commlen + 1, char);
708 memcpy(comment, p, commlen);
709 comment[commlen] = '\0';
711 key->comment = comment;
714 char *fingerprint = ssh2_fingerprint(key->alg, key->data);
715 plog(logctx, logfn, "submitted key: %s %s",
716 fingerprint, key->comment);
720 if (add234(ssh2keys, key) == key) {
723 ret[4] = SSH_AGENT_SUCCESS;
725 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
727 key->alg->freekey(key->data);
731 fail_reason = "key already present";
736 case SSH1_AGENTC_REMOVE_RSA_IDENTITY:
738 * Remove from the list and return SSH_AGENT_SUCCESS, or
739 * perhaps SSH_AGENT_FAILURE if it wasn't in the list to
743 struct RSAKey reqkey, *key;
746 plog(logctx, logfn, "request: SSH1_AGENTC_REMOVE_RSA_IDENTITY");
748 n = makekey(p, msgend - p, &reqkey, NULL, 0);
750 fail_reason = "request truncated before public key";
755 char fingerprint[128];
756 reqkey.comment = NULL;
757 rsa_fingerprint(fingerprint, sizeof(fingerprint), &reqkey);
758 plog(logctx, logfn, "unwanted key: %s", fingerprint);
761 key = find234(rsakeys, &reqkey, NULL);
762 freebn(reqkey.exponent);
763 freebn(reqkey.modulus);
766 plog(logctx, logfn, "found with comment: %s", key->comment);
768 del234(rsakeys, key);
772 ret[4] = SSH_AGENT_SUCCESS;
774 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
776 fail_reason = "key not found";
781 case SSH2_AGENTC_REMOVE_IDENTITY:
783 * Remove from the list and return SSH_AGENT_SUCCESS, or
784 * perhaps SSH_AGENT_FAILURE if it wasn't in the list to
788 struct ssh2_userkey *key;
791 plog(logctx, logfn, "request: SSH2_AGENTC_REMOVE_IDENTITY");
794 fail_reason = "request truncated before public key";
797 b.len = toint(GET_32BIT(p));
800 if (b.len < 0 || b.len > msgend - p) {
801 fail_reason = "request truncated before public key";
808 char *fingerprint = ssh2_fingerprint_blob(b.blob, b.len);
809 plog(logctx, logfn, "unwanted key: %s", fingerprint);
813 key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm);
815 fail_reason = "key not found";
819 plog(logctx, logfn, "found with comment: %s", key->comment);
821 del234(ssh2keys, key);
823 key->alg->freekey(key->data);
826 ret[4] = SSH_AGENT_SUCCESS;
828 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
831 case SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
833 * Remove all SSH-1 keys. Always returns success.
838 plog(logctx, logfn, "request:"
839 " SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES");
841 while ((rkey = index234(rsakeys, 0)) != NULL) {
842 del234(rsakeys, rkey);
849 ret[4] = SSH_AGENT_SUCCESS;
851 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
854 case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
856 * Remove all SSH-2 keys. Always returns success.
859 struct ssh2_userkey *skey;
861 plog(logctx, logfn, "request: SSH2_AGENTC_REMOVE_ALL_IDENTITIES");
863 while ((skey = index234(ssh2keys, 0)) != NULL) {
864 del234(ssh2keys, skey);
865 skey->alg->freekey(skey->data);
871 ret[4] = SSH_AGENT_SUCCESS;
873 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
877 plog(logctx, logfn, "request: unknown message type %d", type);
879 fail_reason = "unrecognised message";
883 * Unrecognised message. Return SSH_AGENT_FAILURE.
886 ret[4] = SSH_AGENT_FAILURE;
887 plog(logctx, logfn, "reply: SSH_AGENT_FAILURE (%s)", fail_reason);
891 *outlen = 4 + GET_32BIT(ret);
895 void *pageant_failure_msg(int *outlen)
897 unsigned char *ret = snewn(5, unsigned char);
899 ret[4] = SSH_AGENT_FAILURE;
904 void pageant_init(void)
906 pageant_local = TRUE;
907 rsakeys = newtree234(cmpkeys_rsa);
908 ssh2keys = newtree234(cmpkeys_ssh2);
911 struct RSAKey *pageant_nth_ssh1_key(int i)
913 return index234(rsakeys, i);
916 struct ssh2_userkey *pageant_nth_ssh2_key(int i)
918 return index234(ssh2keys, i);
921 int pageant_count_ssh1_keys(void)
923 return count234(rsakeys);
926 int pageant_count_ssh2_keys(void)
928 return count234(ssh2keys);
931 int pageant_add_ssh1_key(struct RSAKey *rkey)
933 return add234(rsakeys, rkey) == rkey;
936 int pageant_add_ssh2_key(struct ssh2_userkey *skey)
938 return add234(ssh2keys, skey) == skey;
941 int pageant_delete_ssh1_key(struct RSAKey *rkey)
943 struct RSAKey *deleted = del234(rsakeys, rkey);
946 assert(deleted == rkey);
950 int pageant_delete_ssh2_key(struct ssh2_userkey *skey)
952 struct ssh2_userkey *deleted = del234(ssh2keys, skey);
955 assert(deleted == skey);
959 /* ----------------------------------------------------------------------
964 * Coroutine macros similar to, but simplified from, those in ssh.c.
966 #define crBegin(v) { int *crLine = &v; switch(v) { case 0:;
967 #define crFinish(z) } *crLine = 0; return (z); }
968 #define crGetChar(c) do \
971 *crLine =__LINE__; return 1; case __LINE__:; \
974 (c) = (unsigned char)*data++; \
977 struct pageant_conn_state {
978 const struct plug_function_table *fn;
979 /* the above variable absolutely *must* be the first in this structure */
983 pageant_logfn_t logfn;
984 unsigned char lenbuf[4], pktbuf[AGENT_MAX_MSGLEN];
987 int crLine; /* for coroutine in pageant_conn_receive */
990 static int pageant_conn_closing(Plug plug, const char *error_msg,
991 int error_code, int calling_back)
993 struct pageant_conn_state *pc = (struct pageant_conn_state *)plug;
995 plog(pc->logctx, pc->logfn, "%p: error: %s", pc, error_msg);
997 plog(pc->logctx, pc->logfn, "%p: connection closed", pc);
998 sk_close(pc->connsock);
1003 static void pageant_conn_sent(Plug plug, int bufsize)
1005 /* struct pageant_conn_state *pc = (struct pageant_conn_state *)plug; */
1008 * We do nothing here, because we expect that there won't be a
1009 * need to throttle and unthrottle the connection to an agent -
1010 * clients will typically not send many requests, and will wait
1011 * until they receive each reply before sending a new request.
1015 static void pageant_conn_log(void *logctx, const char *fmt, va_list ap)
1017 /* Wrapper on pc->logfn that prefixes the connection identifier */
1018 struct pageant_conn_state *pc = (struct pageant_conn_state *)logctx;
1019 char *formatted = dupvprintf(fmt, ap);
1020 plog(pc->logctx, pc->logfn, "%p: %s", pc, formatted);
1024 static int pageant_conn_receive(Plug plug, int urgent, char *data, int len)
1026 struct pageant_conn_state *pc = (struct pageant_conn_state *)plug;
1029 crBegin(pc->crLine);
1033 while (pc->got < 4) {
1035 pc->lenbuf[pc->got++] = c;
1038 pc->len = GET_32BIT(pc->lenbuf);
1040 pc->real_packet = (pc->len < AGENT_MAX_MSGLEN-4);
1042 while (pc->got < pc->len) {
1044 if (pc->real_packet)
1045 pc->pktbuf[pc->got] = c;
1053 if (pc->real_packet) {
1054 reply = pageant_handle_msg(pc->pktbuf, pc->len, &replylen, pc,
1055 pc->logfn?pageant_conn_log:NULL);
1057 plog(pc->logctx, pc->logfn, "%p: overlong message (%u)",
1059 plog(pc->logctx, pc->logfn, "%p: reply: SSH_AGENT_FAILURE "
1060 "(message too long)", pc);
1061 reply = pageant_failure_msg(&replylen);
1063 sk_write(pc->connsock, reply, replylen);
1064 smemclr(reply, replylen);
1071 struct pageant_listen_state {
1072 const struct plug_function_table *fn;
1073 /* the above variable absolutely *must* be the first in this structure */
1077 pageant_logfn_t logfn;
1080 static int pageant_listen_closing(Plug plug, const char *error_msg,
1081 int error_code, int calling_back)
1083 struct pageant_listen_state *pl = (struct pageant_listen_state *)plug;
1085 plog(pl->logctx, pl->logfn, "listening socket: error: %s", error_msg);
1086 sk_close(pl->listensock);
1087 pl->listensock = NULL;
1091 static int pageant_listen_accepting(Plug plug,
1092 accept_fn_t constructor, accept_ctx_t ctx)
1094 static const struct plug_function_table connection_fn_table = {
1095 NULL, /* no log function, because that's for outgoing connections */
1096 pageant_conn_closing,
1097 pageant_conn_receive,
1099 NULL /* no accepting function, because we've already done it */
1101 struct pageant_listen_state *pl = (struct pageant_listen_state *)plug;
1102 struct pageant_conn_state *pc;
1106 pc = snew(struct pageant_conn_state);
1107 pc->fn = &connection_fn_table;
1108 pc->logfn = pl->logfn;
1109 pc->logctx = pl->logctx;
1112 pc->connsock = constructor(ctx, (Plug) pc);
1113 if ((err = sk_socket_error(pc->connsock)) != NULL) {
1114 sk_close(pc->connsock);
1119 sk_set_frozen(pc->connsock, 0);
1121 peerinfo = sk_peer_info(pc->connsock);
1123 plog(pl->logctx, pl->logfn, "%p: new connection from %s",
1126 plog(pl->logctx, pl->logfn, "%p: new connection", pc);
1132 struct pageant_listen_state *pageant_listener_new(void)
1134 static const struct plug_function_table listener_fn_table = {
1135 NULL, /* no log function, because that's for outgoing connections */
1136 pageant_listen_closing,
1137 NULL, /* no receive function on a listening socket */
1138 NULL, /* no sent function on a listening socket */
1139 pageant_listen_accepting
1142 struct pageant_listen_state *pl = snew(struct pageant_listen_state);
1143 pl->fn = &listener_fn_table;
1146 pl->listensock = NULL;
1150 void pageant_listener_got_socket(struct pageant_listen_state *pl, Socket sock)
1152 pl->listensock = sock;
1155 void pageant_listener_set_logfn(struct pageant_listen_state *pl,
1156 void *logctx, pageant_logfn_t logfn)
1158 pl->logctx = logctx;
1162 void pageant_listener_free(struct pageant_listen_state *pl)
1165 sk_close(pl->listensock);
1169 /* ----------------------------------------------------------------------
1170 * Code to perform agent operations either as a client, or within the
1171 * same process as the running agent.
1174 static tree234 *passphrases = NULL;
1177 * After processing a list of filenames, we want to forget the
1180 void pageant_forget_passphrases(void)
1182 if (!passphrases) /* in case we never set it up at all */
1185 while (count234(passphrases) > 0) {
1186 char *pp = index234(passphrases, 0);
1187 smemclr(pp, strlen(pp));
1188 delpos234(passphrases, 0);
1193 void *pageant_get_keylist1(int *length)
1197 if (!pageant_local) {
1198 unsigned char request[5], *response;
1202 request[4] = SSH1_AGENTC_REQUEST_RSA_IDENTITIES;
1203 PUT_32BIT(request, 1);
1205 agent_query_synchronous(request, 5, &vresponse, &resplen);
1206 response = vresponse;
1207 if (resplen < 5 || response[4] != SSH1_AGENT_RSA_IDENTITIES_ANSWER) {
1212 ret = snewn(resplen-5, unsigned char);
1213 memcpy(ret, response+5, resplen-5);
1217 *length = resplen-5;
1219 ret = pageant_make_keylist1(length);
1224 void *pageant_get_keylist2(int *length)
1228 if (!pageant_local) {
1229 unsigned char request[5], *response;
1233 request[4] = SSH2_AGENTC_REQUEST_IDENTITIES;
1234 PUT_32BIT(request, 1);
1236 agent_query_synchronous(request, 5, &vresponse, &resplen);
1237 response = vresponse;
1238 if (resplen < 5 || response[4] != SSH2_AGENT_IDENTITIES_ANSWER) {
1243 ret = snewn(resplen-5, unsigned char);
1244 memcpy(ret, response+5, resplen-5);
1248 *length = resplen-5;
1250 ret = pageant_make_keylist2(length);
1255 int pageant_add_keyfile(Filename *filename, const char *passphrase,
1258 struct RSAKey *rkey = NULL;
1259 struct ssh2_userkey *skey = NULL;
1264 const char *this_passphrase;
1265 const char *error = NULL;
1269 passphrases = newtree234(NULL);
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;
1282 * See if the key is already loaded (in the primary Pageant,
1283 * which may or may not be us).
1287 unsigned char *keylist, *p;
1288 int i, nkeys, bloblen, keylistlen;
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;
1295 keylist = pageant_get_keylist1(&keylistlen);
1297 unsigned char *blob2;
1298 blob = ssh2_userkey_loadpub(filename, NULL, &bloblen,
1301 *retstr = dupprintf("Couldn't load private key (%s)", error);
1302 return PAGEANT_ACTION_FAILURE;
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);
1311 keylist = pageant_get_keylist2(&keylistlen);
1314 if (keylistlen < 4) {
1315 *retstr = dupstr("Received broken key list from agent");
1318 return PAGEANT_ACTION_FAILURE;
1320 nkeys = toint(GET_32BIT(keylist));
1322 *retstr = dupstr("Received broken key list from agent");
1325 return PAGEANT_ACTION_FAILURE;
1330 for (i = 0; i < nkeys; i++) {
1331 if (!memcmp(blob, p, bloblen)) {
1332 /* Key is already present; we can now leave. */
1335 return PAGEANT_ACTION_OK;
1337 /* Now skip over public blob */
1338 if (type == SSH_KEYTYPE_SSH1) {
1339 int n = rsa_public_blob_len(p, keylistlen);
1341 *retstr = dupstr("Received broken key list from agent");
1344 return PAGEANT_ACTION_FAILURE;
1350 if (keylistlen < 4) {
1351 *retstr = dupstr("Received broken key list from agent");
1354 return PAGEANT_ACTION_FAILURE;
1360 if (n < 0 || n > keylistlen) {
1361 *retstr = dupstr("Received broken key list from agent");
1364 return PAGEANT_ACTION_FAILURE;
1369 /* Now skip over comment field */
1372 if (keylistlen < 4) {
1373 *retstr = dupstr("Received broken key list from agent");
1376 return PAGEANT_ACTION_FAILURE;
1382 if (n < 0 || n > keylistlen) {
1383 *retstr = dupstr("Received broken key list from agent");
1386 return PAGEANT_ACTION_FAILURE;
1400 if (type == SSH_KEYTYPE_SSH1)
1401 needs_pass = rsakey_encrypted(filename, &comment);
1403 needs_pass = ssh2_userkey_encrypted(filename, &comment);
1405 if (type == SSH_KEYTYPE_SSH1)
1406 rkey = snew(struct RSAKey);
1409 * Loop round repeatedly trying to load the key, until we either
1410 * succeed, fail for some serious reason, or run out of
1411 * passphrases to try.
1417 * If we've been given a passphrase on input, try using
1418 * it. Otherwise, try one from our tree234 of previously
1419 * useful passphrases.
1422 this_passphrase = (attempts == 0 ? passphrase : NULL);
1424 this_passphrase = (const char *)index234(passphrases, attempts);
1427 if (!this_passphrase) {
1429 * Run out of passphrases to try.
1433 return PAGEANT_ACTION_NEED_PP;
1436 this_passphrase = "";
1438 if (type == SSH_KEYTYPE_SSH1)
1439 ret = loadrsakey(filename, rkey, this_passphrase, &error);
1441 skey = ssh2_load_userkey(filename, this_passphrase, &error);
1442 if (skey == SSH2_WRONG_PASSPHRASE)
1452 * Failed to load the key file, for some reason other than
1455 *retstr = dupstr(error);
1457 return PAGEANT_ACTION_FAILURE;
1458 } else if (ret == 1) {
1460 * Successfully loaded the key file.
1465 * Passphrase wasn't right; go round again.
1472 * If we get here, we've succesfully loaded the key into
1473 * rkey/skey, but not yet added it to the agent.
1477 * If the key was successfully decrypted, save the passphrase for
1478 * use with other keys we try to load.
1481 char *pp_copy = dupstr(this_passphrase);
1482 if (addpos234(passphrases, pp_copy, 0) != pp_copy) {
1483 /* No need; it was already there. */
1484 smemclr(pp_copy, strlen(pp_copy));
1492 if (type == SSH_KEYTYPE_SSH1) {
1493 if (!pageant_local) {
1494 unsigned char *request, *response;
1496 int reqlen, clen, resplen;
1498 clen = strlen(rkey->comment);
1500 reqlen = 4 + 1 + /* length, message type */
1502 ssh1_bignum_length(rkey->modulus) +
1503 ssh1_bignum_length(rkey->exponent) +
1504 ssh1_bignum_length(rkey->private_exponent) +
1505 ssh1_bignum_length(rkey->iqmp) +
1506 ssh1_bignum_length(rkey->p) +
1507 ssh1_bignum_length(rkey->q) + 4 + clen /* comment */
1510 request = snewn(reqlen, unsigned char);
1512 request[4] = SSH1_AGENTC_ADD_RSA_IDENTITY;
1514 PUT_32BIT(request + reqlen, bignum_bitcount(rkey->modulus));
1516 reqlen += ssh1_write_bignum(request + reqlen, rkey->modulus);
1517 reqlen += ssh1_write_bignum(request + reqlen, rkey->exponent);
1519 ssh1_write_bignum(request + reqlen,
1520 rkey->private_exponent);
1521 reqlen += ssh1_write_bignum(request + reqlen, rkey->iqmp);
1522 reqlen += ssh1_write_bignum(request + reqlen, rkey->p);
1523 reqlen += ssh1_write_bignum(request + reqlen, rkey->q);
1524 PUT_32BIT(request + reqlen, clen);
1525 memcpy(request + reqlen + 4, rkey->comment, clen);
1527 PUT_32BIT(request, reqlen - 4);
1529 agent_query_synchronous(request, reqlen, &vresponse, &resplen);
1530 response = vresponse;
1531 if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
1532 *retstr = dupstr("The already running Pageant "
1533 "refused to add the key.");
1538 return PAGEANT_ACTION_FAILURE;
1545 if (!pageant_add_ssh1_key(rkey)) {
1547 sfree(rkey); /* already present, don't waste RAM */
1551 if (!pageant_local) {
1552 unsigned char *request, *response;
1554 int reqlen, alglen, clen, keybloblen, resplen;
1555 alglen = strlen(skey->alg->name);
1556 clen = strlen(skey->comment);
1558 keybloblen = skey->alg->openssh_fmtkey(skey->data, NULL, 0);
1560 reqlen = 4 + 1 + /* length, message type */
1561 4 + alglen + /* algorithm name */
1562 keybloblen + /* key data */
1563 4 + clen /* comment */
1566 request = snewn(reqlen, unsigned char);
1568 request[4] = SSH2_AGENTC_ADD_IDENTITY;
1570 PUT_32BIT(request + reqlen, alglen);
1572 memcpy(request + reqlen, skey->alg->name, alglen);
1574 reqlen += skey->alg->openssh_fmtkey(skey->data,
1577 PUT_32BIT(request + reqlen, clen);
1578 memcpy(request + reqlen + 4, skey->comment, clen);
1580 PUT_32BIT(request, reqlen - 4);
1582 agent_query_synchronous(request, reqlen, &vresponse, &resplen);
1583 response = vresponse;
1584 if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
1585 *retstr = dupstr("The already running Pageant "
1586 "refused to add the key.");
1589 return PAGEANT_ACTION_FAILURE;
1595 if (!pageant_add_ssh2_key(skey)) {
1596 skey->alg->freekey(skey->data);
1597 sfree(skey); /* already present, don't waste RAM */
1601 return PAGEANT_ACTION_OK;
1604 int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx,
1607 unsigned char *keylist, *p;
1608 int i, nkeys, keylistlen;
1610 struct pageant_pubkey cbkey;
1612 keylist = pageant_get_keylist1(&keylistlen);
1613 if (keylistlen < 4) {
1614 *retstr = dupstr("Received broken SSH-1 key list from agent");
1616 return PAGEANT_ACTION_FAILURE;
1618 nkeys = toint(GET_32BIT(keylist));
1620 *retstr = dupstr("Received broken SSH-1 key list from agent");
1622 return PAGEANT_ACTION_FAILURE;
1627 for (i = 0; i < nkeys; i++) {
1629 char fingerprint[128];
1632 /* public blob and fingerprint */
1633 memset(&rkey, 0, sizeof(rkey));
1634 n = makekey(p, keylistlen, &rkey, NULL, 0);
1635 if (n < 0 || n > keylistlen) {
1637 *retstr = dupstr("Received broken SSH-1 key list from agent");
1639 return PAGEANT_ACTION_FAILURE;
1641 p += n, keylistlen -= n;
1642 rsa_fingerprint(fingerprint, sizeof(fingerprint), &rkey);
1645 if (keylistlen < 4) {
1646 *retstr = dupstr("Received broken SSH-1 key list from agent");
1649 return PAGEANT_ACTION_FAILURE;
1651 n = toint(GET_32BIT(p));
1652 p += 4, keylistlen -= 4;
1653 if (n < 0 || keylistlen < n) {
1654 *retstr = dupstr("Received broken SSH-1 key list from agent");
1657 return PAGEANT_ACTION_FAILURE;
1659 comment = dupprintf("%.*s", (int)n, (const char *)p);
1660 p += n, keylistlen -= n;
1662 cbkey.blob = rsa_public_blob(&rkey, &cbkey.bloblen);
1663 cbkey.comment = comment;
1664 cbkey.ssh_version = 1;
1665 callback(callback_ctx, fingerprint, comment, &cbkey);
1673 if (keylistlen != 0) {
1674 *retstr = dupstr("Received broken SSH-1 key list from agent");
1675 return PAGEANT_ACTION_FAILURE;
1678 keylist = pageant_get_keylist2(&keylistlen);
1679 if (keylistlen < 4) {
1680 *retstr = dupstr("Received broken SSH-2 key list from agent");
1682 return PAGEANT_ACTION_FAILURE;
1684 nkeys = toint(GET_32BIT(keylist));
1686 *retstr = dupstr("Received broken SSH-2 key list from agent");
1688 return PAGEANT_ACTION_FAILURE;
1693 for (i = 0; i < nkeys; i++) {
1698 if (keylistlen < 4) {
1699 *retstr = dupstr("Received broken SSH-2 key list from agent");
1701 return PAGEANT_ACTION_FAILURE;
1703 n = toint(GET_32BIT(p));
1704 p += 4, keylistlen -= 4;
1705 if (n < 0 || keylistlen < n) {
1706 *retstr = dupstr("Received broken SSH-2 key list from agent");
1708 return PAGEANT_ACTION_FAILURE;
1710 fingerprint = ssh2_fingerprint_blob(p, n);
1713 p += n, keylistlen -= n;
1716 if (keylistlen < 4) {
1717 *retstr = dupstr("Received broken SSH-2 key list from agent");
1720 return PAGEANT_ACTION_FAILURE;
1722 n = toint(GET_32BIT(p));
1723 p += 4, keylistlen -= 4;
1724 if (n < 0 || keylistlen < n) {
1725 *retstr = dupstr("Received broken SSH-2 key list from agent");
1728 return PAGEANT_ACTION_FAILURE;
1730 comment = dupprintf("%.*s", (int)n, (const char *)p);
1731 p += n, keylistlen -= n;
1733 cbkey.ssh_version = 2;
1734 cbkey.comment = comment;
1735 callback(callback_ctx, fingerprint, comment, &cbkey);
1742 if (keylistlen != 0) {
1743 *retstr = dupstr("Received broken SSH-1 key list from agent");
1744 return PAGEANT_ACTION_FAILURE;
1747 return PAGEANT_ACTION_OK;
1750 int pageant_delete_key(struct pageant_pubkey *key, char **retstr)
1752 unsigned char *request, *response;
1753 int reqlen, resplen, ret;
1756 if (key->ssh_version == 1) {
1757 reqlen = 5 + key->bloblen;
1758 request = snewn(reqlen, unsigned char);
1759 PUT_32BIT(request, reqlen - 4);
1760 request[4] = SSH1_AGENTC_REMOVE_RSA_IDENTITY;
1761 memcpy(request + 5, key->blob, key->bloblen);
1763 reqlen = 9 + key->bloblen;
1764 request = snewn(reqlen, unsigned char);
1765 PUT_32BIT(request, reqlen - 4);
1766 request[4] = SSH2_AGENTC_REMOVE_IDENTITY;
1767 PUT_32BIT(request + 5, key->bloblen);
1768 memcpy(request + 9, key->blob, key->bloblen);
1771 agent_query_synchronous(request, reqlen, &vresponse, &resplen);
1772 response = vresponse;
1773 if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
1774 *retstr = dupstr("Agent failed to delete key");
1775 ret = PAGEANT_ACTION_FAILURE;
1778 ret = PAGEANT_ACTION_OK;
1785 int pageant_delete_all_keys(char **retstr)
1787 unsigned char request[5], *response;
1788 int reqlen, resplen, success;
1791 PUT_32BIT(request, 1);
1792 request[4] = SSH2_AGENTC_REMOVE_ALL_IDENTITIES;
1794 agent_query_synchronous(request, reqlen, &vresponse, &resplen);
1795 response = vresponse;
1796 success = (resplen >= 4 && response[4] == SSH_AGENT_SUCCESS);
1799 *retstr = dupstr("Agent failed to delete SSH-2 keys");
1800 return PAGEANT_ACTION_FAILURE;
1803 PUT_32BIT(request, 1);
1804 request[4] = SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
1806 agent_query_synchronous(request, reqlen, &vresponse, &resplen);
1807 response = vresponse;
1808 success = (resplen >= 4 && response[4] == SSH_AGENT_SUCCESS);
1811 *retstr = dupstr("Agent failed to delete SSH-1 keys");
1812 return PAGEANT_ACTION_FAILURE;
1816 return PAGEANT_ACTION_OK;
1819 struct pageant_pubkey *pageant_pubkey_copy(struct pageant_pubkey *key)
1821 struct pageant_pubkey *ret = snew(struct pageant_pubkey);
1822 ret->blob = snewn(key->bloblen, unsigned char);
1823 memcpy(ret->blob, key->blob, key->bloblen);
1824 ret->bloblen = key->bloblen;
1825 ret->comment = key->comment ? dupstr(key->comment) : NULL;
1826 ret->ssh_version = key->ssh_version;
1830 void pageant_pubkey_free(struct pageant_pubkey *key)
1832 sfree(key->comment);