aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Schneider <asn@cryptomilk.org>2011-08-23 20:19:24 +0200
committerAndreas Schneider <asn@cryptomilk.org>2011-08-23 21:54:02 +0200
commit379d65eaaf14c7ad699bb3752a5866ccb614f1af (patch)
tree732d40ad3c59f96209052b556233885eaceca61c
parentaa018c1484ce053bf88dbe066988b5e39a2c0317 (diff)
downloadlibssh-379d65eaaf14c7ad699bb3752a5866ccb614f1af.tar.gz
libssh-379d65eaaf14c7ad699bb3752a5866ccb614f1af.tar.xz
libssh-379d65eaaf14c7ad699bb3752a5866ccb614f1af.zip
auth: Add ssh_userauth_publickey().
-rw-r--r--include/libssh/libssh.h3
-rw-r--r--src/auth.c174
2 files changed, 177 insertions, 0 deletions
diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h
index 89c4258..01d6c52 100644
--- a/include/libssh/libssh.h
+++ b/include/libssh/libssh.h
@@ -497,6 +497,9 @@ LIBSSH_API int ssh_userauth_list(ssh_session session, const char *username);
LIBSSH_API int ssh_userauth_try_publickey(ssh_session session,
const char *username,
const ssh_key pubkey);
+LIBSSH_API int ssh_userauth_publickey(ssh_session session,
+ const char *username,
+ const ssh_key privkey);
#ifndef _WIN32
LIBSSH_API int ssh_userauth_agent_pubkey(ssh_session session, const char *username,
diff --git a/src/auth.c b/src/auth.c
index dac187a..f3dec65 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -630,6 +630,180 @@ fail:
}
/**
+ * @brief Authenticate with public/private key.
+ *
+ * @param[in] ssh_session The SSH session.
+ *
+ * @param[in] username The username, this SHOULD be NULL.
+ *
+ * @param[in] privkey The private key for authentication.
+ *
+ * @return SSH_AUTH_ERROR: A serious error happened.\n
+ * SSH_AUTH_DENIED: The server doesn't accept that public key as an
+ * authentication token. Try another key or another
+ * method.\n
+ * SSH_AUTH_PARTIAL: You've been partially authenticated, you still
+ * have to use another method.\n
+ * SSH_AUTH_SUCCESS: The public key is accepted, you want now to use
+ * ssh_userauth_pubkey().
+ * SSH_AUTH_AGAIN: In nonblocking mode, you've got to call this again
+ * later.
+ *
+ * @note Most server implementations do not permit changing the username during
+ * authentication. The username should only be set with ssh_optoins_set() only
+ * before you connect to the server.
+ */
+int ssh_userauth_publickey(ssh_session session,
+ const char *username,
+ const ssh_key privkey)
+{
+ ssh_string str;
+ int rc;
+
+ if (session == NULL) {
+ return SSH_AUTH_ERROR;
+ }
+
+ if (privkey == NULL || !ssh_key_is_private(privkey)) {
+ ssh_set_error(session, SSH_FATAL, "Invalid private key");
+ return SSH_AUTH_ERROR;
+ }
+
+#ifdef WITH_SSH1
+ if (session->version == 1) {
+ return SSH_AUTH_DENIED;
+ }
+#endif
+
+ switch(session->pending_call_state) {
+ case SSH_PENDING_CALL_NONE:
+ break;
+ case SSH_PENDING_CALL_AUTH_OFFER_PUBKEY:
+ goto pending;
+ default:
+ ssh_set_error(session,
+ SSH_FATAL,
+ "Bad call during pending SSH call in ssh_userauth_try_pubkey");
+ return SSH_ERROR;
+ }
+
+ rc = ssh_userauth_request_service(session);
+ if (rc == SSH_AGAIN) {
+ return SSH_AUTH_AGAIN;
+ } else if (rc == SSH_ERROR) {
+ return SSH_AUTH_ERROR;
+ }
+
+ /* request */
+ rc = buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST);
+ if (rc < 0) {
+ goto fail;
+ }
+
+ /* username */
+ if (username) {
+ str = ssh_string_from_char(username);
+ } else {
+ str = ssh_string_from_char(session->username);
+ }
+ if (str == NULL) {
+ goto fail;
+ }
+
+ rc = buffer_add_ssh_string(session->out_buffer, str);
+ ssh_string_free(str);
+ if (rc < 0) {
+ goto fail;
+ }
+
+ /* service */
+ str = ssh_string_from_char("ssh-connection");
+ if (str == NULL) {
+ goto fail;
+ }
+
+ rc = buffer_add_ssh_string(session->out_buffer, str);
+ ssh_string_free(str);
+ if (rc < 0) {
+ goto fail;
+ }
+
+ /* method */
+ str = ssh_string_from_char("publickey");
+ if (str == NULL) {
+ goto fail;
+ }
+
+ rc = buffer_add_ssh_string(session->out_buffer, str);
+ ssh_string_free(str);
+ if (rc < 0) {
+ goto fail;
+ }
+
+ /* private key? */
+ rc = buffer_add_u8(session->out_buffer, 1);
+ if (rc < 0) {
+ goto fail;
+ }
+
+ /* algo */
+ str = ssh_string_from_char(privkey->type_c);
+ if (rc < 0) {
+ goto fail;
+ }
+
+ rc = buffer_add_ssh_string(session->out_buffer, str);
+ ssh_string_free(str);
+ if (rc < 0) {
+ goto fail;
+ }
+
+ /* public key */
+ str = ssh_pki_export_pubkey_blob(privkey);
+ if (str == NULL) {
+ goto fail;
+ }
+
+ rc = buffer_add_ssh_string(session->out_buffer, str);
+ ssh_string_free(str);
+ if (rc < 0) {
+ goto fail;
+ }
+
+ /* sign the buffer with the private key */
+ str = ssh_pki_do_sign(session, session->out_buffer, privkey);
+ if (str == NULL) {
+ goto fail;
+ }
+
+ rc = buffer_add_ssh_string(session->out_buffer, str);
+ ssh_string_free(str);
+ if (rc < 0) {
+ goto fail;
+ }
+
+ session->auth_state = SSH_AUTH_STATE_NONE;
+ session->pending_call_state = SSH_PENDING_CALL_AUTH_OFFER_PUBKEY;
+ rc = packet_send(session);
+ if (rc == SSH_ERROR) {
+ return SSH_AUTH_ERROR;
+ }
+
+pending:
+ rc = ssh_userauth_get_response(session);
+ if (rc != SSH_AUTH_AGAIN) {
+ session->pending_call_state = SSH_PENDING_CALL_NONE;
+ }
+
+ return rc;
+fail:
+ ssh_set_error_oom(session);
+ buffer_reinit(session->out_buffer);
+
+ return SSH_AUTH_ERROR;
+}
+
+/**
* @brief Try to authenticate through public key (deprecated).
*
* @param[in] session The ssh session to use.