aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libssh/libssh.h2
-rw-r--r--src/auth.c49
-rw-r--r--src/libssh.map1
-rw-r--r--tests/CMakeLists.txt3
-rw-r--r--tests/client/torture_auth.c93
-rw-r--r--tests/keys/id_rsa_protected28
-rw-r--r--tests/keys/id_rsa_protected.pub1
7 files changed, 177 insertions, 0 deletions
diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h
index 12ff322d..d8b35950 100644
--- a/include/libssh/libssh.h
+++ b/include/libssh/libssh.h
@@ -757,6 +757,8 @@ LIBSSH_API int ssh_userauth_publickey(ssh_session session,
LIBSSH_API int ssh_userauth_agent(ssh_session session,
const char *username);
#endif
+LIBSSH_API int ssh_userauth_publickey_auto_get_current_identity(ssh_session session,
+ char** value);
LIBSSH_API int ssh_userauth_publickey_auto(ssh_session session,
const char *username,
const char *passphrase);
diff --git a/src/auth.c b/src/auth.c
index 89272290..fcf39b7a 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -976,6 +976,55 @@ struct ssh_auth_auto_state_struct {
};
/**
+ * @brief Get the identity that is currenly being processed by
+ * ssh_userauth_publickey_auto()
+ *
+ * This is meant to be used by a callback that happens as part of the
+ * execution of ssh_userauth_publickey_auto(). The auth_function
+ * callback might want to know which key a passphrase is needed for,
+ * for example.
+ *
+ * @param[in] session The SSH session.
+ *
+ * @param[out] value The value to get into. As a char**, space will be
+ * allocated by the function for the value, it is
+ * your responsibility to free the memory using
+ * ssh_string_free_char().
+ *
+ * @return SSH_OK on success, SSH_ERROR on error.
+ */
+int ssh_userauth_publickey_auto_get_current_identity(ssh_session session,
+ char** value)
+{
+ const char *id = NULL;
+
+ if (session == NULL) {
+ return SSH_ERROR;
+ }
+
+ if (value == NULL) {
+ ssh_set_error_invalid(session);
+ return SSH_ERROR;
+ }
+
+ if (session->auth.auto_state != NULL && session->auth.auto_state->it != NULL) {
+ id = session->auth.auto_state->it->data;
+ }
+
+ if (id == NULL) {
+ return SSH_ERROR;
+ }
+
+ *value = strdup(id);
+ if (*value == NULL) {
+ ssh_set_error_oom(session);
+ return SSH_ERROR;
+ }
+
+ return SSH_OK;
+}
+
+/**
* @brief Tries to automatically authenticate with public key and "none"
*
* It may fail, for instance it doesn't ask for a password and uses a default
diff --git a/src/libssh.map b/src/libssh.map
index c9bedee0..e30c2449 100644
--- a/src/libssh.map
+++ b/src/libssh.map
@@ -402,6 +402,7 @@ LIBSSH_4_5_0 # Released
ssh_userauth_pubkey;
ssh_userauth_publickey;
ssh_userauth_publickey_auto;
+ ssh_userauth_publickey_auto_get_current_identity;
ssh_userauth_try_publickey;
ssh_version;
ssh_write_knownhost;
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 33a187fb..208d62dd 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -208,6 +208,9 @@ if (CLIENT_TESTING OR SERVER_TESTING)
# Give bob some keys
file(COPY keys/id_rsa DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
file(COPY keys/id_rsa.pub DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
+ # Same as id_rsa, protected with passphrase "secret"
+ file(COPY keys/id_rsa_protected DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
+ file(COPY keys/id_rsa_protected.pub DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
file(COPY keys/id_ecdsa DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
file(COPY keys/id_ecdsa.pub DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
file(COPY keys/id_ed25519 DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
diff --git a/tests/client/torture_auth.c b/tests/client/torture_auth.c
index 24ecc507..29f6f5a5 100644
--- a/tests/client/torture_auth.c
+++ b/tests/client/torture_auth.c
@@ -281,6 +281,96 @@ static void torture_auth_autopubkey(void **state) {
assert_int_equal(rc, SSH_AUTH_SUCCESS);
}
+struct torture_auth_autopubkey_protected_data {
+ ssh_session session;
+ int n_calls;
+};
+
+static int
+torture_auth_autopubkey_protected_auth_function (const char *prompt, char *buf, size_t len,
+ int echo, int verify, void *userdata)
+{
+ int rc;
+ char *id, *expected_id;
+ struct torture_auth_autopubkey_protected_data *data = userdata;
+
+ assert_true(prompt != NULL);
+ assert_int_equal(echo, 0);
+ assert_int_equal(verify, 0);
+
+ expected_id = ssh_path_expand_escape(data->session, "%d/id_rsa_protected");
+ assert_true(expected_id != NULL);
+
+ rc = ssh_userauth_publickey_auto_get_current_identity(data->session, &id);
+ assert_int_equal(rc, SSH_OK);
+
+ assert_string_equal(expected_id, id);
+
+ ssh_string_free_char(id);
+ ssh_string_free_char(expected_id);
+
+ data->n_calls += 1;
+ strncpy(buf, "secret", len);
+ return 0;
+}
+
+static void torture_auth_autopubkey_protected(void **state) {
+ struct torture_state *s = *state;
+ ssh_session session = s->ssh.session;
+ char *id;
+ int rc;
+
+ struct torture_auth_autopubkey_protected_data data = {
+ .session = session,
+ .n_calls = 0
+ };
+
+ struct ssh_callbacks_struct callbacks = {
+ .userdata = &data,
+ .auth_function = torture_auth_autopubkey_protected_auth_function
+ };
+
+ /* no session pointer */
+ rc = ssh_userauth_publickey_auto_get_current_identity(NULL, &id);
+ assert_int_equal(rc, SSH_ERROR);
+
+ /* no result pointer */
+ rc = ssh_userauth_publickey_auto_get_current_identity(session, NULL);
+ assert_int_equal(rc, SSH_ERROR);
+
+ /* no auto auth going on */
+ rc = ssh_userauth_publickey_auto_get_current_identity(session, &id);
+ assert_int_equal(rc, SSH_ERROR);
+
+ ssh_callbacks_init(&callbacks);
+ ssh_set_callbacks(session, &callbacks);
+
+ /* Authenticate as alice with bob his pubkey */
+ rc = ssh_options_set(session, SSH_OPTIONS_USER, TORTURE_SSH_USER_ALICE);
+ assert_int_equal(rc, SSH_OK);
+
+ /* Try id_rsa_protected first.
+ */
+ rc = ssh_options_set(session, SSH_OPTIONS_IDENTITY, "%d/id_rsa_protected");
+ assert_int_equal(rc, SSH_OK);
+
+ rc = ssh_connect(session);
+ assert_int_equal(rc, SSH_OK);
+
+ rc = ssh_userauth_none(session,NULL);
+ /* This request should return a SSH_REQUEST_DENIED error */
+ if (rc == SSH_ERROR) {
+ assert_int_equal(ssh_get_error_code(session), SSH_REQUEST_DENIED);
+ }
+ rc = ssh_userauth_list(session, NULL);
+ assert_true(rc & SSH_AUTH_METHOD_PUBLICKEY);
+
+ rc = ssh_userauth_publickey_auto(session, NULL, NULL);
+ assert_int_equal(rc, SSH_AUTH_SUCCESS);
+
+ assert_int_equal (data.n_calls, 1);
+}
+
static void torture_auth_autopubkey_nonblocking(void **state) {
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
@@ -918,6 +1008,9 @@ int torture_run_tests(void) {
cmocka_unit_test_setup_teardown(torture_auth_autopubkey,
pubkey_setup,
session_teardown),
+ cmocka_unit_test_setup_teardown(torture_auth_autopubkey_protected,
+ pubkey_setup,
+ session_teardown),
cmocka_unit_test_setup_teardown(torture_auth_autopubkey_nonblocking,
pubkey_setup,
session_teardown),
diff --git a/tests/keys/id_rsa_protected b/tests/keys/id_rsa_protected
new file mode 100644
index 00000000..cdf5c2b8
--- /dev/null
+++ b/tests/keys/id_rsa_protected
@@ -0,0 +1,28 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBjmItEMS
+YKDxy/7xvsZY+uAAAAEAAAAAEAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQCz98jP4bLz
+1eNSFd5s2rauzUrREkRlcNt9yh9vXcRIMn19Jt35GUJQzqL5+gRVXbfFZ1qd2zYGSfva0a
+Kclp0iA5ZT6SjGn6BGa0ksT842IAolCpErd44k0EfoC33o0yongbC/nobhbry4+APBRVDB
+UhzoRzpHKmLPsMT5L76BK8FAhVRC3teQ9xc7I3nO6PmoOFkziXpXs6D0taPj/YgXlpy8qN
+8gyl6qaen3PoFNhlC25BTpvVW4RiFfK8zouQzCd2xUaHjqQMoyZFCHIDwDqq8sCWIwyrzy
+TmBHgB4l5OeoNH9DXbQjo8ypg2XpMtOTz8qic448NH9dcZveIXrvAAADwCLre52Jer2DTQ
+TJi91b/xNm5NRuW9366ZdoOC5NdWtbQFk4YJmdImEDo8k1t3Re24rVNxLMQwHwZX4ZLISl
+/e49RtSd6TDP44FkQF4NgtCjLUdmEWRTQj0mtENGto+wdLpL25HkmmI5WGrQU9SufVhhvj
+TxKi6ediSXIXEA5bSrWNvUaw084TT3ZfP9g98/6wr9tAYL1jVfTFUabvZzCR6+wRVoJIVc
+/+uN1bubj+IdOzYSm9Dhj4kUlK+KvI4GtouCzjuEZosjvn0ino3du1vgyT7SPdjmDxtIds
+YI7YiB1Xy3QcWdWFk+SoXhDizf9pupo2r1+G50GoBuXg2ELdsKBLXtxQ9bh37JyAcLzagq
+iVMCJjk3XMZvNXhdELRqLeWyhQ7U1BCtUBatbem0VsH6hQZ/pHReX2We8/GAUQkh4ZN8U2
+lkta9v5cb7XaBm49JjzIa3WeOS+tFHIUAWqd7MQ4f2FCTMhBssLAM7EJDOUXyo6938pa75
++LvdLZRUycE8d/PWG9SuFWSe4CJJrRlBQqPEwx9OPtKNNKgsXIGVKAFLXe+nJ4z6RXTR3R
+IGe0uaf8v9Jra5j22rq/dbQG1fP1fZNcCnIZQQo6olLaoyQmGCboC8CiCz1PNTsC1+r4pB
+oaRiCx5/qLF6EXQ03mdEqL1L/R+KMDa2+Ncw2hCSRU3GBby4wXmSqFsboRy5uxJB5sK0Ut
+sI3FW48k9zijiqVpdysRkalVVSQj8ymTG9LbjjEEmE7qxRf2dZCEnS/iPFUIu7iO9ISiOm
+4ThpROBspNyHMXKFR6mKArJX1vIwjehlaLAXA3UMY9PEFRDrWQcbatGWj4f/L6e3Tq+n7a
+t0djAgKlh40IvVL+Xf+Bsv8vUr7HAbKnOxpX69nEShiJqR5YWlEPXba+JCOjryE2ycoRB6
+d2d0SgDlB1M04uUmv2sy2Kw/CcSNHPLKGiYqqv8DAZ4GiKH2rI4oWvH9z2uRuQni98/Gw1
+1D5/QwJOHpqrUnVat4JXPBeTqiHYYtbTtqJLeIPX+Dsa6tbdjEOVgx2FkH3104xMwJyUKb
+Ccip4AbWsTwfM4GVPnJE6WCBcXC5WR6AOzuEEDQjhyzLs5K7RVb7irfhHa4Vs1/2LvxnRT
+dmTzdv/mhUNqS9RIPmFttfsSveDqY0P6WOn+K6FcCHQjpFJ3pK08glD+Sx4cbFv3lUQLfw
+hsjL0P+p+M+gTqeJ1kb2z87fiS03mHMV15lmb7nzoqyeJLIukV1jidWdGxf0efnQfmUVfX
+Wa+ehGaw==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/tests/keys/id_rsa_protected.pub b/tests/keys/id_rsa_protected.pub
new file mode 100644
index 00000000..15a35b3a
--- /dev/null
+++ b/tests/keys/id_rsa_protected.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCz98jP4bLz1eNSFd5s2rauzUrREkRlcNt9yh9vXcRIMn19Jt35GUJQzqL5+gRVXbfFZ1qd2zYGSfva0aKclp0iA5ZT6SjGn6BGa0ksT842IAolCpErd44k0EfoC33o0yongbC/nobhbry4+APBRVDBUhzoRzpHKmLPsMT5L76BK8FAhVRC3teQ9xc7I3nO6PmoOFkziXpXs6D0taPj/YgXlpy8qN8gyl6qaen3PoFNhlC25BTpvVW4RiFfK8zouQzCd2xUaHjqQMoyZFCHIDwDqq8sCWIwyrzyTmBHgB4l5OeoNH9DXbQjo8ypg2XpMtOTz8qic448NH9dcZveIXrv asn@krikkit.cryptomilk.site