+ fail_reason = "request truncated before p";
+ goto failure;
+ }
+ p += n;
+
+ n = ssh1_read_bignum(p, msgend - p, &key->p); /* q */
+ if (n < 0) {
+ freersakey(key);
+ sfree(key);
+ fail_reason = "request truncated before q";
+ goto failure;
+ }
+ p += n;
+
+ if (msgend < p+4) {
+ freersakey(key);
+ sfree(key);
+ fail_reason = "request truncated before key comment";
+ goto failure;
+ }
+ commentlen = toint(GET_32BIT(p));
+
+ if (commentlen < 0 || commentlen > msgend - p) {
+ freersakey(key);
+ sfree(key);
+ fail_reason = "request truncated before key comment";
+ goto failure;
+ }
+
+ comment = snewn(commentlen+1, char);
+ if (comment) {
+ memcpy(comment, p + 4, commentlen);
+ comment[commentlen] = '\0';
+ key->comment = comment;
+ }
+
+ if (logfn) {
+ char fingerprint[128];
+ rsa_fingerprint(fingerprint, sizeof(fingerprint), key);
+ plog(logctx, logfn, "submitted key: %s", fingerprint);
+ }
+
+ if (add234(rsakeys, key) == key) {
+ keylist_update();
+ PUT_32BIT(ret, 1);
+ ret[4] = SSH_AGENT_SUCCESS;
+
+ plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
+ } else {
+ freersakey(key);
+ sfree(key);
+
+ fail_reason = "key already present";
+ goto failure;
+ }
+ }
+ 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;
+ const char *alg;
+ int alglen, commlen;
+ int bloblen;
+
+ plog(logctx, logfn, "request: SSH2_AGENTC_ADD_IDENTITY");
+
+ if (msgend < p+4) {
+ fail_reason = "request truncated before key algorithm";
+ goto failure;
+ }
+ alglen = toint(GET_32BIT(p));
+ p += 4;
+ if (alglen < 0 || alglen > msgend - p) {
+ fail_reason = "request truncated before key algorithm";
+ goto failure;
+ }
+ alg = (const char *)p;
+ p += alglen;
+
+ key = snew(struct ssh2_userkey);
+ key->alg = find_pubkey_alg_len(alglen, alg);
+ if (!key->alg) {
+ sfree(key);
+ fail_reason = "algorithm unknown";
+ goto failure;
+ }
+
+ bloblen = msgend - p;
+ key->data = key->alg->openssh_createkey(key->alg, &p, &bloblen);
+ if (!key->data) {
+ sfree(key);
+ fail_reason = "key setup failed";
+ 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);
+ fail_reason = "request truncated before key comment";
+ goto failure;
+ }
+ commlen = toint(GET_32BIT(p));
+ p += 4;
+
+ if (commlen < 0 || commlen > msgend - p) {
+ key->alg->freekey(key->data);
+ sfree(key);
+ fail_reason = "request truncated before key comment";
+ goto failure;
+ }
+ comment = snewn(commlen + 1, char);
+ if (comment) {
+ memcpy(comment, p, commlen);
+ comment[commlen] = '\0';
+ }
+ key->comment = comment;
+
+ if (logfn) {
+ char *fingerprint = ssh2_fingerprint(key->alg, key->data);
+ plog(logctx, logfn, "submitted key: %s %s",
+ fingerprint, key->comment);
+ sfree(fingerprint);
+ }
+
+ if (add234(ssh2keys, key) == key) {
+ keylist_update();
+ PUT_32BIT(ret, 1);
+ ret[4] = SSH_AGENT_SUCCESS;
+
+ plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
+ } else {
+ key->alg->freekey(key->data);
+ sfree(key->comment);
+ sfree(key);
+
+ fail_reason = "key already present";
+ goto failure;
+ }
+ }
+ 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;
+
+ plog(logctx, logfn, "request: SSH1_AGENTC_REMOVE_RSA_IDENTITY");
+
+ n = makekey(p, msgend - p, &reqkey, NULL, 0);
+ if (n < 0) {
+ fail_reason = "request truncated before public key";
+ goto failure;
+ }
+
+ if (logfn) {
+ char fingerprint[128];
+ reqkey.comment = NULL;
+ rsa_fingerprint(fingerprint, sizeof(fingerprint), &reqkey);
+ plog(logctx, logfn, "unwanted key: %s", fingerprint);
+ }
+
+ key = find234(rsakeys, &reqkey, NULL);
+ freebn(reqkey.exponent);
+ freebn(reqkey.modulus);
+ PUT_32BIT(ret, 1);
+ if (key) {
+ plog(logctx, logfn, "found with comment: %s", key->comment);
+
+ del234(rsakeys, key);
+ keylist_update();
+ freersakey(key);
+ sfree(key);
+ ret[4] = SSH_AGENT_SUCCESS;
+
+ plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
+ } else {
+ fail_reason = "key not found";
+ goto failure;
+ }
+ }
+ 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;
+
+ plog(logctx, logfn, "request: SSH2_AGENTC_REMOVE_IDENTITY");
+
+ if (msgend < p+4) {
+ fail_reason = "request truncated before public key";
+ goto failure;
+ }
+ b.len = toint(GET_32BIT(p));
+ p += 4;
+
+ if (b.len < 0 || b.len > msgend - p) {
+ fail_reason = "request truncated before public key";
+ goto failure;
+ }
+ b.blob = p;
+ p += b.len;
+
+ if (logfn) {
+ char *fingerprint = ssh2_fingerprint_blob(b.blob, b.len);
+ plog(logctx, logfn, "unwanted key: %s", fingerprint);
+ sfree(fingerprint);
+ }
+
+ key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm);
+ if (!key) {
+ fail_reason = "key not found";
+ goto failure;
+ }
+
+ plog(logctx, logfn, "found with comment: %s", key->comment);
+
+ del234(ssh2keys, key);
+ keylist_update();
+ key->alg->freekey(key->data);
+ sfree(key);
+ PUT_32BIT(ret, 1);
+ ret[4] = SSH_AGENT_SUCCESS;
+
+ plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
+ }
+ break;