diff options
-rw-r--r-- | include/libssh/libssh.h | 2 | ||||
-rw-r--r-- | src/auth.c | 49 | ||||
-rw-r--r-- | src/libssh.map | 1 | ||||
-rw-r--r-- | tests/CMakeLists.txt | 3 | ||||
-rw-r--r-- | tests/client/torture_auth.c | 93 | ||||
-rw-r--r-- | tests/keys/id_rsa_protected | 28 | ||||
-rw-r--r-- | tests/keys/id_rsa_protected.pub | 1 |
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); @@ -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 |