/* * Fetch list of identities held by the agent. */ int ssh_fetch_identitylist(int sock, int version, struct ssh_identitylist **idlp) { u_char type, code1 = 0, code2 = 0; u_int32_t num, i; struct sshbuf *msg; struct ssh_identitylist *idl = NULL; int r; /* Determine request and expected response types */ switch (version) { case 1: code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES; code2 = SSH_AGENT_RSA_IDENTITIES_ANSWER; break; case 2: code1 = SSH2_AGENTC_REQUEST_IDENTITIES; code2 = SSH2_AGENT_IDENTITIES_ANSWER; break; default: return SSH_ERR_INVALID_ARGUMENT; } /* * Send a message to the agent requesting for a list of the * identities it can represent. */ if ((msg = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; if ((r = sshbuf_put_u8(msg, code1)) != 0) goto out; if ((r = ssh_request_reply(sock, msg, msg)) != 0) goto out; /* Get message type, and verify that we got a proper answer. */ if ((r = sshbuf_get_u8(msg, &type)) != 0) goto out; if (agent_failed(type)) { r = SSH_ERR_AGENT_FAILURE; goto out; } else if (type != code2) { r = SSH_ERR_INVALID_FORMAT; goto out; } /* Get the number of entries in the response and check it for sanity. */ if ((r = sshbuf_get_u32(msg, &num)) != 0) goto out; if (num > MAX_AGENT_IDENTITIES) { r = SSH_ERR_INVALID_FORMAT; goto out; } if (num == 0) { r = SSH_ERR_AGENT_NO_IDENTITIES; goto out; } /* Deserialise the response into a list of keys/comments */ if ((idl = calloc(1, sizeof(*idl))) == NULL || (idl->keys = calloc(num, sizeof(*idl->keys))) == NULL || (idl->comments = calloc(num, sizeof(*idl->comments))) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } for (i = 0; i < num;) { switch (version) { case 1: #ifdef WITH_SSH1 if ((r = deserialise_identity1(msg, &(idl->keys[i]), &(idl->comments[i]))) != 0) goto out; #endif break; case 2: if ((r = deserialise_identity2(msg, &(idl->keys[i]), &(idl->comments[i]))) != 0) { if (r == SSH_ERR_KEY_TYPE_UNKNOWN) { /* Gracefully skip unknown key types */ num--; continue; } else goto out; } break; } i++; } idl->nkeys = num; *idlp = idl; idl = NULL; r = 0; out: sshbuf_free(msg); if (idl != NULL) ssh_free_identitylist(idl); return r; }
/* * Checks if the user has an authentication agent, and if so, tries to * authenticate using the agent. */ static int try_agent_authentication(struct ssh *ssh) { int r, type, agent_fd, ret = 0; u_char response[16]; size_t i; BIGNUM *challenge; struct ssh_identitylist *idlist = NULL; /* Get connection to the agent. */ if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) { if (r != SSH_ERR_AGENT_NOT_PRESENT) debug("%s: ssh_get_authentication_socket: %s", __func__, ssh_err(r)); return 0; } if ((challenge = BN_new()) == NULL) fatal("try_agent_authentication: BN_new failed"); /* Loop through identities served by the agent. */ if ((r = ssh_fetch_identitylist(agent_fd, 1, &idlist)) != 0) { if (r != SSH_ERR_AGENT_NO_IDENTITIES) debug("%s: ssh_fetch_identitylist: %s", __func__, ssh_err(r)); goto out; } for (i = 0; i < idlist->nkeys; i++) { /* Try this identity. */ debug("Trying RSA authentication via agent with '%.100s'", idlist->comments[i]); /* * Tell the server that we are willing to authenticate * using this key. */ if ((r = sshpkt_start(ssh, SSH_CMSG_AUTH_RSA)) != 0 || (r = sshpkt_put_bignum1(ssh, idlist->keys[i]->rsa->n)) != 0 || (r = sshpkt_send(ssh)) != 0) fatal("%s: %s", __func__, ssh_err(r)); ssh_packet_write_wait(ssh); /* Wait for server's response. */ type = ssh_packet_read(ssh); /* The server sends failure if it doesn't like our key or does not support RSA authentication. */ if (type == SSH_SMSG_FAILURE) { debug("Server refused our key."); continue; } /* Otherwise it should have sent a challenge. */ if (type != SSH_SMSG_AUTH_RSA_CHALLENGE) ssh_packet_disconnect(ssh, "Protocol error during RSA " "authentication: %d", type); if ((r = sshpkt_get_bignum1(ssh, challenge)) != 0 || (r = sshpkt_get_end(ssh)) != 0) fatal("%s: %s", __func__, ssh_err(r)); debug("Received RSA challenge from server."); /* Ask the agent to decrypt the challenge. */ if ((r = ssh_decrypt_challenge(agent_fd, idlist->keys[i], challenge, session_id, response)) != 0) { /* * The agent failed to authenticate this identifier * although it advertised it supports this. Just * return a wrong value. */ logit("Authentication agent failed to decrypt " "challenge: %s", ssh_err(r)); memset(response, 0, sizeof(response)); } debug("Sending response to RSA challenge."); /* Send the decrypted challenge back to the server. */ if ((r = sshpkt_start(ssh, SSH_CMSG_AUTH_RSA_RESPONSE)) != 0 || (r = sshpkt_put(ssh, &response, sizeof(response))) != 0 || (r = sshpkt_send(ssh)) != 0) fatal("%s: %s", __func__, ssh_err(r)); ssh_packet_write_wait(ssh); /* Wait for response from the server. */ type = ssh_packet_read(ssh); /* * The server returns success if it accepted the * authentication. */ if (type == SSH_SMSG_SUCCESS) { debug("RSA authentication accepted by server."); ret = 1; break; } else if (type != SSH_SMSG_FAILURE) ssh_packet_disconnect(ssh, "Protocol error waiting RSA auth " "response: %d", type); } if (ret != 1) debug("RSA authentication using agent refused."); out: ssh_free_identitylist(idlist); ssh_close_authentication_socket(agent_fd); BN_clear_free(challenge); return ret; }