- PUT_32BIT(p, nkeys);
- p += 4;
- for (i = 0; NULL != (key = index234(ssh2keys, i)); i++) {
- blob = key->alg->public_blob(key->data, &bloblen);
- PUT_32BIT(p, bloblen);
- p += 4;
- memcpy(p, blob, bloblen);
- p += bloblen;
- sfree(blob);
- PUT_32BIT(p, strlen(key->comment));
- memcpy(p + 4, key->comment, strlen(key->comment));
- p += 4 + strlen(key->comment);
- }
-
- assert(p - ret == len);
- return ret;
-}
-
-/*
- * Acquire a keylist1 from the primary Pageant; this means either
- * calling make_keylist1 (if that's us) or sending a message to the
- * primary Pageant (if it's not).
- */
-static void *get_keylist1(int *length)
-{
- void *ret;
-
- if (already_running) {
- unsigned char request[5], *response;
- void *vresponse;
- int resplen, retval;
- request[4] = SSH1_AGENTC_REQUEST_RSA_IDENTITIES;
- PUT_32BIT(request, 4);
-
- retval = agent_query(request, 5, &vresponse, &resplen, NULL, NULL);
- assert(retval == 1);
- response = vresponse;
- if (resplen < 5 || response[4] != SSH1_AGENT_RSA_IDENTITIES_ANSWER)
- return NULL;
-
- ret = snewn(resplen-5, unsigned char);
- memcpy(ret, response+5, resplen-5);
- sfree(response);
-
- if (length)
- *length = resplen-5;
- } else {
- ret = make_keylist1(length);
- }
- return ret;
-}
-
-/*
- * Acquire a keylist2 from the primary Pageant; this means either
- * calling make_keylist2 (if that's us) or sending a message to the
- * primary Pageant (if it's not).
- */
-static void *get_keylist2(int *length)
-{
- void *ret;
-
- if (already_running) {
- unsigned char request[5], *response;
- void *vresponse;
- int resplen, retval;
-
- request[4] = SSH2_AGENTC_REQUEST_IDENTITIES;
- PUT_32BIT(request, 4);
-
- retval = agent_query(request, 5, &vresponse, &resplen, NULL, NULL);
- assert(retval == 1);
- response = vresponse;
- if (resplen < 5 || response[4] != SSH2_AGENT_IDENTITIES_ANSWER)
- return NULL;
-
- ret = snewn(resplen-5, unsigned char);
- memcpy(ret, response+5, resplen-5);
- sfree(response);
-
- if (length)
- *length = resplen-5;
- } else {
- ret = make_keylist2(length);
- }
- return ret;
-}
-
-/*
- * This is the main agent function that answers messages.
- */
-static void answer_msg(void *msg)
-{
- unsigned char *p = msg;
- unsigned char *ret = msg;
- unsigned char *msgend;
- int type;
-
- /*
- * Get the message length.
- */
- msgend = p + 4 + GET_32BIT(p);
-
- /*
- * Get the message type.
- */
- if (msgend < p+5)
- goto failure;
- type = p[4];
-
- p += 5;
- switch (type) {
- case SSH1_AGENTC_REQUEST_RSA_IDENTITIES:
- /*
- * Reply with SSH1_AGENT_RSA_IDENTITIES_ANSWER.
- */
- {
- int len;
- void *keylist;
-
- ret[4] = SSH1_AGENT_RSA_IDENTITIES_ANSWER;
- keylist = make_keylist1(&len);
- if (len + 5 > AGENT_MAX_MSGLEN) {
- sfree(keylist);
- goto failure;
- }
- PUT_32BIT(ret, len + 1);
- memcpy(ret + 5, keylist, len);
- sfree(keylist);
- }
- break;
- case SSH2_AGENTC_REQUEST_IDENTITIES:
- /*
- * Reply with SSH2_AGENT_IDENTITIES_ANSWER.
- */
- {
- int len;
- void *keylist;
-
- ret[4] = SSH2_AGENT_IDENTITIES_ANSWER;
- keylist = make_keylist2(&len);
- if (len + 5 > AGENT_MAX_MSGLEN) {
- sfree(keylist);
- goto failure;
- }
- PUT_32BIT(ret, len + 1);
- memcpy(ret + 5, keylist, len);
- sfree(keylist);
- }
- break;
- case SSH1_AGENTC_RSA_CHALLENGE:
- /*
- * Reply with either SSH1_AGENT_RSA_RESPONSE or
- * SSH_AGENT_FAILURE, depending on whether we have that key
- * or not.
- */
- {
- struct RSAKey reqkey, *key;
- Bignum challenge, response;
- unsigned char response_source[48], response_md5[16];
- struct MD5Context md5c;
- int i, len;
-
- p += 4;
- i = ssh1_read_bignum(p, msgend - p, &reqkey.exponent);
- if (i < 0)
- goto failure;
- p += i;
- i = ssh1_read_bignum(p, msgend - p, &reqkey.modulus);
- if (i < 0)
- goto failure;
- p += i;
- i = ssh1_read_bignum(p, msgend - p, &challenge);
- if (i < 0)
- goto failure;
- p += i;
- if (msgend < p+16) {
- freebn(reqkey.exponent);
- freebn(reqkey.modulus);
- freebn(challenge);
- goto failure;
- }
- memcpy(response_source + 32, p, 16);
- p += 16;
- if (msgend < p+4 ||
- GET_32BIT(p) != 1 ||
- (key = find234(rsakeys, &reqkey, NULL)) == NULL) {
- freebn(reqkey.exponent);
- freebn(reqkey.modulus);
- freebn(challenge);
- goto failure;
- }
- response = rsadecrypt(challenge, key);
- for (i = 0; i < 32; i++)
- response_source[i] = bignum_byte(response, 31 - i);
-
- MD5Init(&md5c);
- MD5Update(&md5c, response_source, 48);
- MD5Final(response_md5, &md5c);
- memset(response_source, 0, 48); /* burn the evidence */
- freebn(response); /* and that evidence */
- freebn(challenge); /* yes, and that evidence */
- freebn(reqkey.exponent); /* and free some memory ... */
- freebn(reqkey.modulus); /* ... while we're at it. */
-
- /*
- * Packet is the obvious five byte header, plus sixteen
- * bytes of MD5.
- */
- len = 5 + 16;
- PUT_32BIT(ret, len - 4);
- ret[4] = SSH1_AGENT_RSA_RESPONSE;
- memcpy(ret + 5, response_md5, 16);
- }
- break;
- case SSH2_AGENTC_SIGN_REQUEST:
- /*
- * Reply with either SSH2_AGENT_SIGN_RESPONSE or
- * SSH_AGENT_FAILURE, depending on whether we have that key
- * or not.
- */
- {
- struct ssh2_userkey *key;
- struct blob b;
- unsigned char *data, *signature;
- int datalen, siglen, len;
-
- if (msgend < p+4)
- goto failure;
- b.len = GET_32BIT(p);
- p += 4;
- if (msgend < p+b.len)
- goto failure;
- b.blob = p;
- p += b.len;
- if (msgend < p+4)
- goto failure;
- datalen = GET_32BIT(p);
- p += 4;
- if (msgend < p+datalen)
- goto failure;
- data = p;
- key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm);
- if (!key)
- goto failure;
- signature = key->alg->sign(key->data, data, datalen, &siglen);
- len = 5 + 4 + siglen;
- PUT_32BIT(ret, len - 4);
- ret[4] = SSH2_AGENT_SIGN_RESPONSE;
- PUT_32BIT(ret + 5, siglen);
- memcpy(ret + 5 + 4, signature, siglen);
- sfree(signature);
- }
- break;
- case SSH1_AGENTC_ADD_RSA_IDENTITY:
- /*
- * Add to the list and return SSH_AGENT_SUCCESS, or
- * SSH_AGENT_FAILURE if the key was malformed.
- */
- {
- struct RSAKey *key;
- char *comment;
- int n, commentlen;
-
- key = snew(struct RSAKey);
- memset(key, 0, sizeof(struct RSAKey));
-
- n = makekey(p, msgend - p, key, NULL, 1);
- if (n < 0) {
- freersakey(key);
- sfree(key);
- goto failure;
- }
- p += n;
-
- n = makeprivate(p, msgend - p, key);
- if (n < 0) {
- freersakey(key);
- sfree(key);
- goto failure;
- }
- p += n;
-
- n = ssh1_read_bignum(p, msgend - p, &key->iqmp); /* p^-1 mod q */
- if (n < 0) {
- freersakey(key);
- sfree(key);
- goto failure;
- }
- p += n;
-
- n = ssh1_read_bignum(p, msgend - p, &key->p); /* p */
- if (n < 0) {
- freersakey(key);
- sfree(key);
- goto failure;
- }
- p += n;
-
- n = ssh1_read_bignum(p, msgend - p, &key->q); /* q */
- if (n < 0) {
- freersakey(key);
- sfree(key);
- goto failure;
- }
- p += n;
-
- if (msgend < p+4) {
- freersakey(key);
- sfree(key);
- goto failure;
- }
- commentlen = GET_32BIT(p);
-
- if (msgend < p+commentlen) {
- freersakey(key);
- sfree(key);
- goto failure;
- }
-
- comment = snewn(commentlen+1, char);
- if (comment) {
- memcpy(comment, p + 4, commentlen);
- comment[commentlen] = '\0';
- key->comment = comment;
- }
- PUT_32BIT(ret, 1);
- ret[4] = SSH_AGENT_FAILURE;
- if (add234(rsakeys, key) == key) {
- keylist_update();
- ret[4] = SSH_AGENT_SUCCESS;
- } else {
- freersakey(key);
- sfree(key);
- }
- }
- break;
- case SSH2_AGENTC_ADD_IDENTITY:
- /*
- * Add to the list and return SSH_AGENT_SUCCESS, or
- * SSH_AGENT_FAILURE if the key was malformed.
- */
- {
- struct ssh2_userkey *key;
- char *comment, *alg;
- int alglen, commlen;
- int bloblen;
-
-
- if (msgend < p+4)
- goto failure;
- alglen = GET_32BIT(p);
- p += 4;
- if (msgend < p+alglen)
- goto failure;
- alg = p;
- p += alglen;
-
- key = snew(struct ssh2_userkey);
- /* Add further algorithm names here. */
- if (alglen == 7 && !memcmp(alg, "ssh-rsa", 7))
- key->alg = &ssh_rsa;
- else if (alglen == 7 && !memcmp(alg, "ssh-dss", 7))
- key->alg = &ssh_dss;
- else {
- sfree(key);
- goto failure;
- }
-
- bloblen = msgend - p;
- key->data = key->alg->openssh_createkey(&p, &bloblen);
- if (!key->data) {
- sfree(key);
- goto failure;
- }
-
- /*
- * p has been advanced by openssh_createkey, but
- * certainly not _beyond_ the end of the buffer.
- */
- assert(p <= msgend);
-
- if (msgend < p+4) {
- key->alg->freekey(key->data);
- sfree(key);
- goto failure;
- }
- commlen = GET_32BIT(p);
- p += 4;
-
- if (msgend < p+commlen) {
- key->alg->freekey(key->data);
- sfree(key);
- goto failure;
- }
- comment = snewn(commlen + 1, char);
- if (comment) {
- memcpy(comment, p, commlen);
- comment[commlen] = '\0';
- }
- key->comment = comment;
-
- PUT_32BIT(ret, 1);
- ret[4] = SSH_AGENT_FAILURE;
- if (add234(ssh2keys, key) == key) {
- keylist_update();
- ret[4] = SSH_AGENT_SUCCESS;
- } else {
- key->alg->freekey(key->data);
- sfree(key->comment);
- sfree(key);
- }
- }
- break;
- case SSH1_AGENTC_REMOVE_RSA_IDENTITY:
- /*
- * Remove from the list and return SSH_AGENT_SUCCESS, or
- * perhaps SSH_AGENT_FAILURE if it wasn't in the list to
- * start with.
- */
- {
- struct RSAKey reqkey, *key;
- int n;
-
- n = makekey(p, msgend - p, &reqkey, NULL, 0);
- if (n < 0)
- goto failure;
-
- key = find234(rsakeys, &reqkey, NULL);
- freebn(reqkey.exponent);
- freebn(reqkey.modulus);
- PUT_32BIT(ret, 1);
- ret[4] = SSH_AGENT_FAILURE;
- if (key) {
- del234(rsakeys, key);
- keylist_update();
- freersakey(key);
- sfree(key);
- ret[4] = SSH_AGENT_SUCCESS;
- }
- }
- break;
- case SSH2_AGENTC_REMOVE_IDENTITY:
- /*
- * Remove from the list and return SSH_AGENT_SUCCESS, or
- * perhaps SSH_AGENT_FAILURE if it wasn't in the list to
- * start with.
- */
- {
- struct ssh2_userkey *key;
- struct blob b;
-
- if (msgend < p+4)
- goto failure;
- b.len = GET_32BIT(p);
- p += 4;
-
- if (msgend < p+b.len)
- goto failure;
- b.blob = p;
- p += b.len;
-
- key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm);
- if (!key)
- goto failure;
-
- PUT_32BIT(ret, 1);
- ret[4] = SSH_AGENT_FAILURE;
- if (key) {
- del234(ssh2keys, key);
- keylist_update();
- key->alg->freekey(key->data);
- sfree(key);
- ret[4] = SSH_AGENT_SUCCESS;
- }
- }
- break;
- case SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
- /*
- * Remove all SSH1 keys. Always returns success.
- */
- {
- struct RSAKey *rkey;