- 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) {
- freebn(reqkey.exponent);
- goto failure;
- }
- p += i;
- i = ssh1_read_bignum(p, msgend - p, &challenge);
- if (i < 0) {
- freebn(reqkey.exponent);
- freebn(reqkey.modulus);
- 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);
- smemclr(response_source, 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 = toint(GET_32BIT(p));
- if (b.len < 0 || b.len > msgend - (p+4))
- goto failure;
- p += 4;
- b.blob = p;
- p += b.len;
- if (msgend < p+4)
- goto failure;
- datalen = toint(GET_32BIT(p));
- p += 4;
- if (datalen < 0 || datalen > msgend - p)
- 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 = toint(GET_32BIT(p));
-
- if (commentlen < 0 || commentlen > msgend - p) {
- 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 = toint(GET_32BIT(p));
- p += 4;
- if (alglen < 0 || alglen > msgend - p)
- 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 if (alglen == 19 && memcmp(alg, "ecdsa-sha2-nistp256", 19))
- key->alg = &ssh_ecdsa_nistp256;
- else if (alglen == 19 && memcmp(alg, "ecdsa-sha2-nistp384", 19))
- key->alg = &ssh_ecdsa_nistp384;
- else if (alglen == 19 && memcmp(alg, "ecdsa-sha2-nistp521", 19))
- key->alg = &ssh_ecdsa_nistp521;
- 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 = toint(GET_32BIT(p));
- p += 4;
-
- if (commlen < 0 || commlen > msgend - p) {
- 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 = toint(GET_32BIT(p));
- p += 4;
-
- if (b.len < 0 || b.len > msgend - p)
- 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 SSH-1 keys. Always returns success.
- */
- {
- struct RSAKey *rkey;
-
- while ((rkey = index234(rsakeys, 0)) != NULL) {
- del234(rsakeys, rkey);
- freersakey(rkey);
- sfree(rkey);
- }
- keylist_update();
-
- PUT_32BIT(ret, 1);
- ret[4] = SSH_AGENT_SUCCESS;
- }
- break;
- case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
- /*
- * Remove all SSH-2 keys. Always returns success.
- */
- {
- struct ssh2_userkey *skey;
-
- while ((skey = index234(ssh2keys, 0)) != NULL) {
- del234(ssh2keys, skey);
- skey->alg->freekey(skey->data);
- sfree(skey);
- }
- keylist_update();
-
- PUT_32BIT(ret, 1);
- ret[4] = SSH_AGENT_SUCCESS;
- }
- break;
- default:
- failure:
- /*
- * Unrecognised message. Return SSH_AGENT_FAILURE.
- */
- PUT_32BIT(ret, 1);
- ret[4] = SSH_AGENT_FAILURE;
- break;
- }
-}
-
-/*
- * Key comparison function for the 2-3-4 tree of RSA keys.
- */
-static int cmpkeys_rsa(void *av, void *bv)
-{
- struct RSAKey *a = (struct RSAKey *) av;
- struct RSAKey *b = (struct RSAKey *) bv;
- Bignum am, bm;
- int alen, blen;
-
- am = a->modulus;
- bm = b->modulus;
- /*
- * Compare by length of moduli.
- */
- alen = bignum_bitcount(am);
- blen = bignum_bitcount(bm);
- if (alen > blen)
- return +1;
- else if (alen < blen)
- return -1;
- /*
- * Now compare by moduli themselves.
- */
- alen = (alen + 7) / 8; /* byte count */
- while (alen-- > 0) {
- int abyte, bbyte;
- abyte = bignum_byte(am, alen);
- bbyte = bignum_byte(bm, alen);
- if (abyte > bbyte)
- return +1;
- else if (abyte < bbyte)
- return -1;
- }
- /*
- * Give up.
- */
- return 0;
-}
-
-/*
- * Key comparison function for the 2-3-4 tree of SSH-2 keys.
- */
-static int cmpkeys_ssh2(void *av, void *bv)
-{
- struct ssh2_userkey *a = (struct ssh2_userkey *) av;
- struct ssh2_userkey *b = (struct ssh2_userkey *) bv;
- int i;
- int alen, blen;
- unsigned char *ablob, *bblob;
- int c;
-
- /*
- * Compare purely by public blob.
- */
- ablob = a->alg->public_blob(a->data, &alen);
- bblob = b->alg->public_blob(b->data, &blen);
-
- c = 0;
- for (i = 0; i < alen && i < blen; i++) {
- if (ablob[i] < bblob[i]) {
- c = -1;
- break;
- } else if (ablob[i] > bblob[i]) {
- c = +1;
- break;
- }