mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-03-24 20:40:09 +09:00
agent: Add support for SSH2_AGENTC_REMOVE_IDENTITY
Implement support for the SSH2_AGENTC_REMOVE_IDENTITY agent protocol message. The implementation mirrors ssh_agent_sign_data() and reuses agent_talk(). A single cleanup path is used to ensure proper resource handling. Signed-off-by: Madhav Vasisth <mv2363@srmist.edu.in> Reviewed-by: Jakub Jelen <jjelen@redhat.com>
This commit is contained in:
committed by
Jakub Jelen
parent
8d563f90f3
commit
8782fcec18
@@ -176,6 +176,17 @@ ssh_key ssh_agent_get_next_ident(struct ssh_session_struct *session,
|
||||
ssh_string ssh_agent_sign_data(ssh_session session,
|
||||
const ssh_key pubkey,
|
||||
struct ssh_buffer_struct *data);
|
||||
/**
|
||||
* @brief Remove an identity from the SSH agent.
|
||||
*
|
||||
* @param session The SSH session.
|
||||
* @param key The public key to remove.
|
||||
*
|
||||
* @return `SSH_OK` on success, `SSH_ERROR` on failure.
|
||||
*/
|
||||
int ssh_agent_remove_identity(ssh_session session,
|
||||
const ssh_key key);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
88
src/agent.c
88
src/agent.c
@@ -635,3 +635,91 @@ ssh_string ssh_agent_sign_data(ssh_session session,
|
||||
|
||||
return sig_blob;
|
||||
}
|
||||
|
||||
int ssh_agent_remove_identity(ssh_session session,
|
||||
const ssh_key key)
|
||||
{
|
||||
ssh_buffer request = NULL;
|
||||
ssh_buffer reply = NULL;
|
||||
ssh_string key_blob = NULL;
|
||||
uint8_t type = 0;
|
||||
int rc = SSH_ERROR;
|
||||
|
||||
if (session == NULL || key == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (session->agent == NULL) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"No agent connection available");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Connect to the agent if not already connected */
|
||||
if (!ssh_socket_is_open(session->agent->sock)) {
|
||||
if (agent_connect(session) < 0) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Could not connect to SSH agent");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
request = ssh_buffer_new();
|
||||
if (request == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ssh_buffer_add_u8(request, SSH2_AGENTC_REMOVE_IDENTITY) < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ssh_pki_export_pubkey_blob(key, &key_blob) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Failed to export public key blob");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ssh_buffer_add_ssh_string(request, key_blob) < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
reply = ssh_buffer_new();
|
||||
if (reply == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (agent_talk(session, request, reply) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ssh_buffer_get_u8(reply, &type) != sizeof(uint8_t)) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Failed to read agent reply type");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (agent_failed(type)) {
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Agent reports failure removing identity");
|
||||
goto fail;
|
||||
} else if (type != SSH_AGENT_SUCCESS) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Agent refused to remove identity: reply type %u",
|
||||
type);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = SSH_OK;
|
||||
|
||||
fail:
|
||||
SSH_STRING_FREE(key_blob);
|
||||
SSH_BUFFER_FREE(request);
|
||||
SSH_BUFFER_FREE(reply);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "libssh/callbacks.h"
|
||||
#include "libssh/libssh.h"
|
||||
#include <libssh/agent.h>
|
||||
#include "libssh/priv.h"
|
||||
|
||||
#include <errno.h>
|
||||
@@ -286,6 +287,96 @@ static void torture_auth_agent_forwarding(void **state)
|
||||
}
|
||||
}
|
||||
|
||||
static int agent_session_setup(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
int verbosity = torture_libssh_verbosity();
|
||||
int rc;
|
||||
|
||||
s->ssh.ssh.session = ssh_new();
|
||||
assert_non_null(s->ssh.ssh.session);
|
||||
|
||||
rc = ssh_options_set(s->ssh.ssh.session,
|
||||
SSH_OPTIONS_LOG_VERBOSITY,
|
||||
&verbosity);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
|
||||
/* No callbacks needed — only talking to the local agent.
|
||||
* The group setup already started the agent and loaded keys.
|
||||
* Do NOT call torture_setup_ssh_agent here — that would spawn
|
||||
* a second agent and overwrite SSH_AUTH_SOCK. */
|
||||
s->ssh.ssh.cb_state = NULL;
|
||||
s->ssh.ssh.callbacks = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void torture_agent_remove_identity(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
ssh_session session = s->ssh.ssh.session;
|
||||
ssh_key key = NULL;
|
||||
char *comment = NULL;
|
||||
uint32_t count_before = 0;
|
||||
uint32_t count_after = 0;
|
||||
int rc;
|
||||
|
||||
assert_non_null(session);
|
||||
|
||||
assert_true(ssh_agent_is_running(session));
|
||||
|
||||
count_before = ssh_agent_get_ident_count(session);
|
||||
|
||||
assert_true(count_before > 0);
|
||||
|
||||
key = ssh_agent_get_first_ident(session, &comment);
|
||||
assert_non_null(key);
|
||||
assert_non_null(comment);
|
||||
|
||||
rc = ssh_agent_remove_identity(session, key);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
|
||||
count_after = ssh_agent_get_ident_count(session);
|
||||
assert_int_equal(count_after, count_before - 1);
|
||||
|
||||
ssh_key_free(key);
|
||||
ssh_string_free_char(comment);
|
||||
}
|
||||
|
||||
static void torture_agent_remove_identity_negative(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
ssh_session session = s->ssh.ssh.session;
|
||||
int rc;
|
||||
|
||||
assert_non_null(session);
|
||||
|
||||
/* NULL key should return SSH_ERROR */
|
||||
rc = ssh_agent_remove_identity(session, NULL);
|
||||
assert_int_equal(rc, SSH_ERROR);
|
||||
}
|
||||
|
||||
static void torture_agent_remove_identity_nonexistent(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
ssh_session session = s->ssh.ssh.session;
|
||||
ssh_key key = NULL;
|
||||
int rc;
|
||||
|
||||
assert_non_null(session);
|
||||
assert_true(ssh_agent_is_running(session));
|
||||
|
||||
rc = ssh_pki_generate_key(SSH_KEYTYPE_RSA, NULL, &key);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
assert_non_null(key);
|
||||
|
||||
/* Key not in agent should fail */
|
||||
rc = ssh_agent_remove_identity(session, key);
|
||||
assert_int_equal(rc, SSH_ERROR);
|
||||
|
||||
ssh_key_free(key);
|
||||
}
|
||||
|
||||
/* Session setup function that configures SSH agent */
|
||||
static int session_setup(void **state)
|
||||
{
|
||||
@@ -300,7 +391,6 @@ static int session_setup(void **state)
|
||||
/* Create a new session */
|
||||
s->ssh.ssh.session = ssh_new();
|
||||
assert_non_null(s->ssh.ssh.session);
|
||||
|
||||
rc = ssh_options_set(s->ssh.ssh.session,
|
||||
SSH_OPTIONS_LOG_VERBOSITY,
|
||||
&verbosity);
|
||||
@@ -342,19 +432,32 @@ static int session_setup(void **state)
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test_setup_teardown(torture_auth_agent_forwarding,
|
||||
session_setup,
|
||||
session_teardown),
|
||||
|
||||
cmocka_unit_test_setup_teardown(torture_agent_remove_identity,
|
||||
agent_session_setup,
|
||||
session_teardown),
|
||||
|
||||
cmocka_unit_test_setup_teardown(torture_agent_remove_identity_negative,
|
||||
agent_session_setup,
|
||||
session_teardown),
|
||||
|
||||
cmocka_unit_test_setup_teardown(torture_agent_remove_identity_nonexistent,
|
||||
agent_session_setup,
|
||||
session_teardown),
|
||||
};
|
||||
|
||||
ssh_init();
|
||||
|
||||
/* Simplify the CMocka test filter handling */
|
||||
#if defined HAVE_CMOCKA_SET_TEST_FILTER
|
||||
cmocka_set_message_output(CM_OUTPUT_STDOUT);
|
||||
#endif
|
||||
|
||||
/* Apply test filtering */
|
||||
torture_filter_tests(tests);
|
||||
|
||||
rc = cmocka_run_group_tests(tests,
|
||||
@@ -365,5 +468,4 @@ int torture_run_tests(void)
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user