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 char *fingerprint_ssh2_blob(const void *blob, int bloblen)
264 unsigned char digest[16];
265 char fingerprint_str[16*3];
269 MD5Simple(blob, bloblen, digest);
270 for (i = 0; i < 16; i++)
271 sprintf(fingerprint_str + i*3, "%02x%s", digest[i], i==15 ? "" : ":");
273 stringlen = GET_32BIT((const unsigned char *)blob);
274 if (stringlen < bloblen-4)
275 return dupprintf("%.*s %s", (int)stringlen, (const char *)blob + 4,
278 return dupstr(fingerprint_str);
281 static void plog(void *logctx, pageant_logfn_t logfn, const char *fmt, ...)
283 __attribute__ ((format (printf, 3, 4)))
287 static void plog(void *logctx, pageant_logfn_t logfn, const char *fmt, ...)
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.
300 logfn(logctx, fmt, ap);
305 void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
306 void *logctx, pageant_logfn_t logfn)
308 const unsigned char *p = msg;
309 const unsigned char *msgend;
310 unsigned char *ret = snewn(AGENT_MAX_MSGLEN, unsigned char);
312 const char *fail_reason;
317 * Get the message type.
320 fail_reason = "message contained no type code";
326 case SSH1_AGENTC_REQUEST_RSA_IDENTITIES:
328 * Reply with SSH1_AGENT_RSA_IDENTITIES_ANSWER.
334 plog(logctx, logfn, "request: SSH1_AGENTC_REQUEST_RSA_IDENTITIES");
336 ret[4] = SSH1_AGENT_RSA_IDENTITIES_ANSWER;
337 keylist = pageant_make_keylist1(&len);
338 if (len + 5 > AGENT_MAX_MSGLEN) {
340 fail_reason = "output would exceed max msglen";
343 PUT_32BIT(ret, len + 1);
344 memcpy(ret + 5, keylist, len);
346 plog(logctx, logfn, "reply: SSH1_AGENT_RSA_IDENTITIES_ANSWER");
347 if (logfn) { /* skip this loop if not logging */
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);
359 case SSH2_AGENTC_REQUEST_IDENTITIES:
361 * Reply with SSH2_AGENT_IDENTITIES_ANSWER.
367 plog(logctx, logfn, "request: SSH2_AGENTC_REQUEST_IDENTITIES");
369 ret[4] = SSH2_AGENT_IDENTITIES_ANSWER;
370 keylist = pageant_make_keylist2(&len);
371 if (len + 5 > AGENT_MAX_MSGLEN) {
373 fail_reason = "output would exceed max msglen";
376 PUT_32BIT(ret, len + 1);
377 memcpy(ret + 5, keylist, len);
379 plog(logctx, logfn, "reply: SSH2_AGENT_IDENTITIES_ANSWER");
380 if (logfn) { /* skip this loop if not logging */
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);
394 case SSH1_AGENTC_RSA_CHALLENGE:
396 * Reply with either SSH1_AGENT_RSA_RESPONSE or
397 * SSH_AGENT_FAILURE, depending on whether we have that key
401 struct RSAKey reqkey, *key;
402 Bignum challenge, response;
403 unsigned char response_source[48], response_md5[16];
404 struct MD5Context md5c;
407 plog(logctx, logfn, "request: SSH1_AGENTC_RSA_CHALLENGE");
410 i = ssh1_read_bignum(p, msgend - p, &reqkey.exponent);
412 fail_reason = "request truncated before key exponent";
416 i = ssh1_read_bignum(p, msgend - p, &reqkey.modulus);
418 freebn(reqkey.exponent);
419 fail_reason = "request truncated before key modulus";
423 i = ssh1_read_bignum(p, msgend - p, &challenge);
425 freebn(reqkey.exponent);
426 freebn(reqkey.modulus);
427 fail_reason = "request truncated before challenge";
432 freebn(reqkey.exponent);
433 freebn(reqkey.modulus);
435 fail_reason = "request truncated before session id";
438 memcpy(response_source + 32, p, 16);
441 freebn(reqkey.exponent);
442 freebn(reqkey.modulus);
444 fail_reason = "request truncated before response type";
447 if (GET_32BIT(p) != 1) {
448 freebn(reqkey.exponent);
449 freebn(reqkey.modulus);
451 fail_reason = "response type other than 1 not supported";
455 char fingerprint[128];
456 reqkey.comment = NULL;
457 rsa_fingerprint(fingerprint, sizeof(fingerprint), &reqkey);
458 plog(logctx, logfn, "requested key: %s", fingerprint);
460 if ((key = find234(rsakeys, &reqkey, NULL)) == NULL) {
461 freebn(reqkey.exponent);
462 freebn(reqkey.modulus);
464 fail_reason = "key not found";
467 response = rsadecrypt(challenge, key);
468 for (i = 0; i < 32; i++)
469 response_source[i] = bignum_byte(response, 31 - i);
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. */
481 * Packet is the obvious five byte header, plus sixteen
485 PUT_32BIT(ret, len - 4);
486 ret[4] = SSH1_AGENT_RSA_RESPONSE;
487 memcpy(ret + 5, response_md5, 16);
489 plog(logctx, logfn, "reply: SSH1_AGENT_RSA_RESPONSE");
492 case SSH2_AGENTC_SIGN_REQUEST:
494 * Reply with either SSH2_AGENT_SIGN_RESPONSE or
495 * SSH_AGENT_FAILURE, depending on whether we have that key
499 struct ssh2_userkey *key;
501 const unsigned char *data;
502 unsigned char *signature;
503 int datalen, siglen, len;
505 plog(logctx, logfn, "request: SSH2_AGENTC_SIGN_REQUEST");
508 fail_reason = "request truncated before public key";
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";
520 fail_reason = "request truncated before string to sign";
523 datalen = toint(GET_32BIT(p));
525 if (datalen < 0 || datalen > msgend - p) {
526 fail_reason = "request truncated before string to sign";
531 char *fingerprint = fingerprint_ssh2_blob(b.blob, b.len);
532 plog(logctx, logfn, "requested key: %s", fingerprint);
535 key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm);
537 fail_reason = "key not found";
540 signature = key->alg->sign(key->data, (const char *)data,
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);
549 plog(logctx, logfn, "reply: SSH2_AGENT_SIGN_RESPONSE");
552 case SSH1_AGENTC_ADD_RSA_IDENTITY:
554 * Add to the list and return SSH_AGENT_SUCCESS, or
555 * SSH_AGENT_FAILURE if the key was malformed.
562 plog(logctx, logfn, "request: SSH1_AGENTC_ADD_RSA_IDENTITY");
564 key = snew(struct RSAKey);
565 memset(key, 0, sizeof(struct RSAKey));
567 n = makekey(p, msgend - p, key, NULL, 1);
571 fail_reason = "request truncated before public key";
576 n = makeprivate(p, msgend - p, key);
580 fail_reason = "request truncated before private key";
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. */
589 n = ssh1_read_bignum(p, msgend - p, &key->iqmp); /* p^-1 mod q */
593 fail_reason = "request truncated before iqmp";
598 n = ssh1_read_bignum(p, msgend - p, &key->q); /* p */
602 fail_reason = "request truncated before p";
607 n = ssh1_read_bignum(p, msgend - p, &key->p); /* q */
611 fail_reason = "request truncated before q";
619 fail_reason = "request truncated before key comment";
622 commentlen = toint(GET_32BIT(p));
624 if (commentlen < 0 || commentlen > msgend - p) {
627 fail_reason = "request truncated before key comment";
631 comment = snewn(commentlen+1, char);
633 memcpy(comment, p + 4, commentlen);
634 comment[commentlen] = '\0';
635 key->comment = comment;
639 char fingerprint[128];
640 rsa_fingerprint(fingerprint, sizeof(fingerprint), key);
641 plog(logctx, logfn, "submitted key: %s", fingerprint);
644 if (add234(rsakeys, key) == key) {
647 ret[4] = SSH_AGENT_SUCCESS;
649 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
654 fail_reason = "key already present";
659 case SSH2_AGENTC_ADD_IDENTITY:
661 * Add to the list and return SSH_AGENT_SUCCESS, or
662 * SSH_AGENT_FAILURE if the key was malformed.
665 struct ssh2_userkey *key;
671 plog(logctx, logfn, "request: SSH2_AGENTC_ADD_IDENTITY");
674 fail_reason = "request truncated before key algorithm";
677 alglen = toint(GET_32BIT(p));
679 if (alglen < 0 || alglen > msgend - p) {
680 fail_reason = "request truncated before key algorithm";
683 alg = (const char *)p;
686 key = snew(struct ssh2_userkey);
687 key->alg = find_pubkey_alg_len(alglen, alg);
690 fail_reason = "algorithm unknown";
694 bloblen = msgend - p;
695 key->data = key->alg->openssh_createkey(&p, &bloblen);
698 fail_reason = "key setup failed";
703 * p has been advanced by openssh_createkey, but
704 * certainly not _beyond_ the end of the buffer.
709 key->alg->freekey(key->data);
711 fail_reason = "request truncated before key comment";
714 commlen = toint(GET_32BIT(p));
717 if (commlen < 0 || commlen > msgend - p) {
718 key->alg->freekey(key->data);
720 fail_reason = "request truncated before key comment";
723 comment = snewn(commlen + 1, char);
725 memcpy(comment, p, commlen);
726 comment[commlen] = '\0';
728 key->comment = comment;
731 char *fingerprint = key->alg->fingerprint(key->data);
732 plog(logctx, logfn, "submitted key: %s %s",
733 fingerprint, key->comment);
737 if (add234(ssh2keys, key) == key) {
740 ret[4] = SSH_AGENT_SUCCESS;
742 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
744 key->alg->freekey(key->data);
748 fail_reason = "key already present";
753 case SSH1_AGENTC_REMOVE_RSA_IDENTITY:
755 * Remove from the list and return SSH_AGENT_SUCCESS, or
756 * perhaps SSH_AGENT_FAILURE if it wasn't in the list to
760 struct RSAKey reqkey, *key;
763 plog(logctx, logfn, "request: SSH1_AGENTC_REMOVE_RSA_IDENTITY");
765 n = makekey(p, msgend - p, &reqkey, NULL, 0);
767 fail_reason = "request truncated before public key";
772 char fingerprint[128];
773 reqkey.comment = NULL;
774 rsa_fingerprint(fingerprint, sizeof(fingerprint), &reqkey);
775 plog(logctx, logfn, "unwanted key: %s", fingerprint);
778 key = find234(rsakeys, &reqkey, NULL);
779 freebn(reqkey.exponent);
780 freebn(reqkey.modulus);
783 plog(logctx, logfn, "found with comment: %s", key->comment);
785 del234(rsakeys, key);
789 ret[4] = SSH_AGENT_SUCCESS;
791 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
793 fail_reason = "key not found";
798 case SSH2_AGENTC_REMOVE_IDENTITY:
800 * Remove from the list and return SSH_AGENT_SUCCESS, or
801 * perhaps SSH_AGENT_FAILURE if it wasn't in the list to
805 struct ssh2_userkey *key;
808 plog(logctx, logfn, "request: SSH2_AGENTC_REMOVE_IDENTITY");
811 fail_reason = "request truncated before public key";
814 b.len = toint(GET_32BIT(p));
817 if (b.len < 0 || b.len > msgend - p) {
818 fail_reason = "request truncated before public key";
825 char *fingerprint = fingerprint_ssh2_blob(b.blob, b.len);
826 plog(logctx, logfn, "unwanted key: %s", fingerprint);
830 key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm);
832 fail_reason = "key not found";
836 plog(logctx, logfn, "found with comment: %s", key->comment);
838 del234(ssh2keys, key);
840 key->alg->freekey(key->data);
843 ret[4] = SSH_AGENT_SUCCESS;
845 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
848 case SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
850 * Remove all SSH-1 keys. Always returns success.
855 plog(logctx, logfn, "request:"
856 " SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES");
858 while ((rkey = index234(rsakeys, 0)) != NULL) {
859 del234(rsakeys, rkey);
866 ret[4] = SSH_AGENT_SUCCESS;
868 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
871 case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
873 * Remove all SSH-2 keys. Always returns success.
876 struct ssh2_userkey *skey;
878 plog(logctx, logfn, "request: SSH2_AGENTC_REMOVE_ALL_IDENTITIES");
880 while ((skey = index234(ssh2keys, 0)) != NULL) {
881 del234(ssh2keys, skey);
882 skey->alg->freekey(skey->data);
888 ret[4] = SSH_AGENT_SUCCESS;
890 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
894 plog(logctx, logfn, "request: unknown message type %d", type);
896 fail_reason = "unrecognised message";
900 * Unrecognised message. Return SSH_AGENT_FAILURE.
903 ret[4] = SSH_AGENT_FAILURE;
904 plog(logctx, logfn, "reply: SSH_AGENT_FAILURE (%s)", fail_reason);
908 *outlen = 4 + GET_32BIT(ret);
912 void *pageant_failure_msg(int *outlen)
914 unsigned char *ret = snewn(5, unsigned char);
916 ret[4] = SSH_AGENT_FAILURE;
921 void pageant_init(void)
923 pageant_local = TRUE;
924 rsakeys = newtree234(cmpkeys_rsa);
925 ssh2keys = newtree234(cmpkeys_ssh2);
928 struct RSAKey *pageant_nth_ssh1_key(int i)
930 return index234(rsakeys, i);
933 struct ssh2_userkey *pageant_nth_ssh2_key(int i)
935 return index234(ssh2keys, i);
938 int pageant_count_ssh1_keys(void)
940 return count234(rsakeys);
943 int pageant_count_ssh2_keys(void)
945 return count234(ssh2keys);
948 int pageant_add_ssh1_key(struct RSAKey *rkey)
950 return add234(rsakeys, rkey) == rkey;
953 int pageant_add_ssh2_key(struct ssh2_userkey *skey)
955 return add234(ssh2keys, skey) == skey;
958 int pageant_delete_ssh1_key(struct RSAKey *rkey)
960 struct RSAKey *deleted = del234(rsakeys, rkey);
963 assert(deleted == rkey);
967 int pageant_delete_ssh2_key(struct ssh2_userkey *skey)
969 struct ssh2_userkey *deleted = del234(ssh2keys, skey);
972 assert(deleted == skey);
976 /* ----------------------------------------------------------------------
981 * Coroutine macros similar to, but simplified from, those in ssh.c.
983 #define crBegin(v) { int *crLine = &v; switch(v) { case 0:;
984 #define crFinish(z) } *crLine = 0; return (z); }
985 #define crGetChar(c) do \
988 *crLine =__LINE__; return 1; case __LINE__:; \
991 (c) = (unsigned char)*data++; \
994 struct pageant_conn_state {
995 const struct plug_function_table *fn;
996 /* the above variable absolutely *must* be the first in this structure */
1000 pageant_logfn_t logfn;
1001 unsigned char lenbuf[4], pktbuf[AGENT_MAX_MSGLEN];
1004 int crLine; /* for coroutine in pageant_conn_receive */
1007 static int pageant_conn_closing(Plug plug, const char *error_msg,
1008 int error_code, int calling_back)
1010 struct pageant_conn_state *pc = (struct pageant_conn_state *)plug;
1012 plog(pc->logctx, pc->logfn, "%p: error: %s", pc, error_msg);
1014 plog(pc->logctx, pc->logfn, "%p: connection closed", pc);
1015 sk_close(pc->connsock);
1020 static void pageant_conn_sent(Plug plug, int bufsize)
1022 /* struct pageant_conn_state *pc = (struct pageant_conn_state *)plug; */
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.
1032 static void pageant_conn_log(void *logctx, const char *fmt, va_list ap)
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);
1041 static int pageant_conn_receive(Plug plug, int urgent, char *data, int len)
1043 struct pageant_conn_state *pc = (struct pageant_conn_state *)plug;
1046 crBegin(pc->crLine);
1050 while (pc->got < 4) {
1052 pc->lenbuf[pc->got++] = c;
1055 pc->len = GET_32BIT(pc->lenbuf);
1057 pc->real_packet = (pc->len < AGENT_MAX_MSGLEN-4);
1059 while (pc->got < pc->len) {
1061 if (pc->real_packet)
1062 pc->pktbuf[pc->got] = c;
1070 if (pc->real_packet) {
1071 reply = pageant_handle_msg(pc->pktbuf, pc->len, &replylen, pc,
1072 pc->logfn?pageant_conn_log:NULL);
1074 plog(pc->logctx, pc->logfn, "%p: overlong message (%u)",
1076 plog(pc->logctx, pc->logfn, "%p: reply: SSH_AGENT_FAILURE "
1077 "(message too long)", pc);
1078 reply = pageant_failure_msg(&replylen);
1080 sk_write(pc->connsock, reply, replylen);
1081 smemclr(reply, replylen);
1088 struct pageant_listen_state {
1089 const struct plug_function_table *fn;
1090 /* the above variable absolutely *must* be the first in this structure */
1094 pageant_logfn_t logfn;
1097 static int pageant_listen_closing(Plug plug, const char *error_msg,
1098 int error_code, int calling_back)
1100 struct pageant_listen_state *pl = (struct pageant_listen_state *)plug;
1102 plog(pl->logctx, pl->logfn, "listening socket: error: %s", error_msg);
1103 sk_close(pl->listensock);
1104 pl->listensock = NULL;
1108 static int pageant_listen_accepting(Plug plug,
1109 accept_fn_t constructor, accept_ctx_t ctx)
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,
1116 NULL /* no accepting function, because we've already done it */
1118 struct pageant_listen_state *pl = (struct pageant_listen_state *)plug;
1119 struct pageant_conn_state *pc;
1122 pc = snew(struct pageant_conn_state);
1123 pc->fn = &connection_fn_table;
1124 pc->logfn = pl->logfn;
1125 pc->logctx = pl->logctx;
1128 pc->connsock = constructor(ctx, (Plug) pc);
1129 if ((err = sk_socket_error(pc->connsock)) != NULL) {
1130 sk_close(pc->connsock);
1135 sk_set_frozen(pc->connsock, 0);
1137 /* FIXME: can we get any useful peer id info? */
1138 plog(pl->logctx, pl->logfn, "%p: new connection", pc);
1143 struct pageant_listen_state *pageant_listener_new(void)
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
1153 struct pageant_listen_state *pl = snew(struct pageant_listen_state);
1154 pl->fn = &listener_fn_table;
1157 pl->listensock = NULL;
1161 void pageant_listener_got_socket(struct pageant_listen_state *pl, Socket sock)
1163 pl->listensock = sock;
1166 void pageant_listener_set_logfn(struct pageant_listen_state *pl,
1167 void *logctx, pageant_logfn_t logfn)
1169 pl->logctx = logctx;
1173 void pageant_listener_free(struct pageant_listen_state *pl)
1176 sk_close(pl->listensock);
1180 /* ----------------------------------------------------------------------
1181 * Code to perform agent operations either as a client, or within the
1182 * same process as the running agent.
1185 static tree234 *passphrases = NULL;
1188 * After processing a list of filenames, we want to forget the
1191 void pageant_forget_passphrases(void)
1193 while (count234(passphrases) > 0) {
1194 char *pp = index234(passphrases, 0);
1195 smemclr(pp, strlen(pp));
1196 delpos234(passphrases, 0);
1201 void *pageant_get_keylist1(int *length)
1205 if (!pageant_local) {
1206 unsigned char request[5], *response;
1208 int resplen, retval;
1209 request[4] = SSH1_AGENTC_REQUEST_RSA_IDENTITIES;
1210 PUT_32BIT(request, 1);
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) {
1220 ret = snewn(resplen-5, unsigned char);
1221 memcpy(ret, response+5, resplen-5);
1225 *length = resplen-5;
1227 ret = pageant_make_keylist1(length);
1232 void *pageant_get_keylist2(int *length)
1236 if (!pageant_local) {
1237 unsigned char request[5], *response;
1239 int resplen, retval;
1241 request[4] = SSH2_AGENTC_REQUEST_IDENTITIES;
1242 PUT_32BIT(request, 1);
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) {
1252 ret = snewn(resplen-5, unsigned char);
1253 memcpy(ret, response+5, resplen-5);
1257 *length = resplen-5;
1259 ret = pageant_make_keylist2(length);
1264 int pageant_add_keyfile(Filename *filename, const char *passphrase,
1267 struct RSAKey *rkey = NULL;
1268 struct ssh2_userkey *skey = NULL;
1273 const char *this_passphrase;
1274 const char *error = NULL;
1278 passphrases = newtree234(NULL);
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;
1291 * See if the key is already loaded (in the primary Pageant,
1292 * which may or may not be us).
1296 unsigned char *keylist, *p;
1297 int i, nkeys, bloblen, keylistlen;
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;
1304 keylist = pageant_get_keylist1(&keylistlen);
1306 unsigned char *blob2;
1307 blob = ssh2_userkey_loadpub(filename, NULL, &bloblen,
1310 *retstr = dupprintf("Couldn't load private key (%s)", error);
1311 return PAGEANT_ACTION_FAILURE;
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);
1320 keylist = pageant_get_keylist2(&keylistlen);
1323 if (keylistlen < 4) {
1324 *retstr = dupstr("Received broken key list from agent");
1325 return PAGEANT_ACTION_FAILURE;
1327 nkeys = toint(GET_32BIT(keylist));
1329 *retstr = dupstr("Received broken key list from agent");
1330 return PAGEANT_ACTION_FAILURE;
1335 for (i = 0; i < nkeys; i++) {
1336 if (!memcmp(blob, p, bloblen)) {
1337 /* Key is already present; we can now leave. */
1340 return PAGEANT_ACTION_OK;
1342 /* Now skip over public blob */
1343 if (type == SSH_KEYTYPE_SSH1) {
1344 int n = rsa_public_blob_len(p, keylistlen);
1346 *retstr = dupstr("Received broken key list from agent");
1347 return PAGEANT_ACTION_FAILURE;
1353 if (keylistlen < 4) {
1354 *retstr = dupstr("Received broken key list from agent");
1355 return PAGEANT_ACTION_FAILURE;
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;
1365 /* Now skip over comment field */
1368 if (keylistlen < 4) {
1369 *retstr = dupstr("Received broken key list from agent");
1370 return PAGEANT_ACTION_FAILURE;
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;
1389 if (type == SSH_KEYTYPE_SSH1)
1390 needs_pass = rsakey_encrypted(filename, &comment);
1392 needs_pass = ssh2_userkey_encrypted(filename, &comment);
1394 if (type == SSH_KEYTYPE_SSH1)
1395 rkey = snew(struct RSAKey);
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.
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.
1411 this_passphrase = (attempts == 0 ? passphrase : NULL);
1413 this_passphrase = (const char *)index234(passphrases, attempts);
1416 if (!this_passphrase) {
1418 * Run out of passphrases to try.
1421 return PAGEANT_ACTION_NEED_PP;
1424 this_passphrase = "";
1426 if (type == SSH_KEYTYPE_SSH1)
1427 ret = loadrsakey(filename, rkey, this_passphrase, &error);
1429 skey = ssh2_load_userkey(filename, this_passphrase, &error);
1430 if (skey == SSH2_WRONG_PASSPHRASE)
1440 * Failed to load the key file, for some reason other than
1443 *retstr = dupstr(error);
1444 return PAGEANT_ACTION_FAILURE;
1445 } else if (ret == 1) {
1447 * Successfully loaded the key file.
1452 * Passphrase wasn't right; go round again.
1459 * If we get here, we've succesfully loaded the key into
1460 * rkey/skey, but not yet added it to the agent.
1464 * If the key was successfully decrypted, save the passphrase for
1465 * use with other keys we try to load.
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));
1479 if (type == SSH_KEYTYPE_SSH1) {
1480 if (!pageant_local) {
1481 unsigned char *request, *response;
1483 int reqlen, clen, resplen, ret;
1485 clen = strlen(rkey->comment);
1487 reqlen = 4 + 1 + /* length, message type */
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 */
1497 request = snewn(reqlen, unsigned char);
1499 request[4] = SSH1_AGENTC_ADD_RSA_IDENTITY;
1501 PUT_32BIT(request + reqlen, bignum_bitcount(rkey->modulus));
1503 reqlen += ssh1_write_bignum(request + reqlen, rkey->modulus);
1504 reqlen += ssh1_write_bignum(request + reqlen, rkey->exponent);
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);
1514 PUT_32BIT(request, reqlen - 4);
1516 ret = agent_query(request, reqlen, &vresponse, &resplen,
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;
1528 if (!pageant_add_ssh1_key(rkey)) {
1529 sfree(rkey); /* already present, don't waste RAM */
1533 if (!pageant_local) {
1534 unsigned char *request, *response;
1536 int reqlen, alglen, clen, keybloblen, resplen, ret;
1537 alglen = strlen(skey->alg->name);
1538 clen = strlen(skey->comment);
1540 keybloblen = skey->alg->openssh_fmtkey(skey->data, NULL, 0);
1542 reqlen = 4 + 1 + /* length, message type */
1543 4 + alglen + /* algorithm name */
1544 keybloblen + /* key data */
1545 4 + clen /* comment */
1548 request = snewn(reqlen, unsigned char);
1550 request[4] = SSH2_AGENTC_ADD_IDENTITY;
1552 PUT_32BIT(request + reqlen, alglen);
1554 memcpy(request + reqlen, skey->alg->name, alglen);
1556 reqlen += skey->alg->openssh_fmtkey(skey->data,
1559 PUT_32BIT(request + reqlen, clen);
1560 memcpy(request + reqlen + 4, skey->comment, clen);
1562 PUT_32BIT(request, reqlen - 4);
1564 ret = agent_query(request, reqlen, &vresponse, &resplen,
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;
1577 if (!pageant_add_ssh2_key(skey)) {
1578 skey->alg->freekey(skey->data);
1579 sfree(skey); /* already present, don't waste RAM */
1583 return PAGEANT_ACTION_OK;
1586 int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx,
1589 unsigned char *keylist, *p;
1590 int i, nkeys, keylistlen;
1593 keylist = pageant_get_keylist1(&keylistlen);
1594 if (keylistlen < 4) {
1595 *retstr = dupstr("Received broken SSH-1 key list from agent");
1597 return PAGEANT_ACTION_FAILURE;
1599 nkeys = toint(GET_32BIT(keylist));
1601 *retstr = dupstr("Received broken SSH-1 key list from agent");
1603 return PAGEANT_ACTION_FAILURE;
1608 for (i = 0; i < nkeys; i++) {
1610 char fingerprint[128];
1613 /* public blob and fingerprint */
1614 memset(&rkey, 0, sizeof(rkey));
1615 n = makekey(p, keylistlen, &rkey, NULL, 0);
1616 if (n < 0 || n > keylistlen) {
1618 *retstr = dupstr("Received broken SSH-1 key list from agent");
1620 return PAGEANT_ACTION_FAILURE;
1622 p += n, keylistlen -= n;
1623 rsa_fingerprint(fingerprint, sizeof(fingerprint), &rkey);
1626 if (keylistlen < 4) {
1627 *retstr = dupstr("Received broken SSH-1 key list from agent");
1630 return PAGEANT_ACTION_FAILURE;
1632 n = toint(GET_32BIT(p));
1633 p += 4, keylistlen -= 4;
1634 if (n < 0 || keylistlen < n) {
1635 *retstr = dupstr("Received broken SSH-1 key list from agent");
1638 return PAGEANT_ACTION_FAILURE;
1640 comment = dupprintf("%.*s", (int)n, (const char *)p);
1641 p += n, keylistlen -= n;
1643 callback(callback_ctx, fingerprint, comment);
1650 if (keylistlen != 0) {
1651 *retstr = dupstr("Received broken SSH-1 key list from agent");
1652 return PAGEANT_ACTION_FAILURE;
1655 keylist = pageant_get_keylist2(&keylistlen);
1656 if (keylistlen < 4) {
1657 *retstr = dupstr("Received broken SSH-2 key list from agent");
1659 return PAGEANT_ACTION_FAILURE;
1661 nkeys = toint(GET_32BIT(keylist));
1663 *retstr = dupstr("Received broken SSH-2 key list from agent");
1665 return PAGEANT_ACTION_FAILURE;
1670 for (i = 0; i < nkeys; i++) {
1675 if (keylistlen < 4) {
1676 *retstr = dupstr("Received broken SSH-2 key list from agent");
1678 return PAGEANT_ACTION_FAILURE;
1680 n = toint(GET_32BIT(p));
1681 p += 4, keylistlen -= 4;
1682 if (n < 0 || keylistlen < n) {
1683 *retstr = dupstr("Received broken SSH-2 key list from agent");
1685 return PAGEANT_ACTION_FAILURE;
1687 fingerprint = fingerprint_ssh2_blob(p, n);
1688 p += n, keylistlen -= n;
1691 if (keylistlen < 4) {
1692 *retstr = dupstr("Received broken SSH-2 key list from agent");
1695 return PAGEANT_ACTION_FAILURE;
1697 n = toint(GET_32BIT(p));
1698 p += 4, keylistlen -= 4;
1699 if (n < 0 || keylistlen < n) {
1700 *retstr = dupstr("Received broken SSH-2 key list from agent");
1703 return PAGEANT_ACTION_FAILURE;
1705 comment = dupprintf("%.*s", (int)n, (const char *)p);
1706 p += n, keylistlen -= n;
1708 callback(callback_ctx, fingerprint, comment);
1715 if (keylistlen != 0) {
1716 *retstr = dupstr("Received broken SSH-1 key list from agent");
1717 return PAGEANT_ACTION_FAILURE;
1720 return PAGEANT_ACTION_OK;