Пример #1
0
/*
 * 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;
}
Пример #2
0
/*
 * 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;
}