diff options
author | milo <milo.sshiva@gmail.com> | 2009-07-27 17:59:02 +0200 |
---|---|---|
committer | Andreas Schneider <mail@cynapses.org> | 2009-07-27 20:27:07 +0200 |
commit | e8f7801540e8be8b029b09269196773767a5983e (patch) | |
tree | 8cc08e3cbcc4e919f132fae4a5cde91bea8e7e94 | |
parent | cdde79418a86da1c9579a022ec8c4ed73fe29f1a (diff) | |
download | libssh-e8f7801540e8be8b029b09269196773767a5983e.tar.gz libssh-e8f7801540e8be8b029b09269196773767a5983e.tar.xz libssh-e8f7801540e8be8b029b09269196773767a5983e.zip |
Public key authentication server side
-rw-r--r-- | include/libssh/priv.h | 5 | ||||
-rw-r--r-- | include/libssh/server.h | 2 | ||||
-rw-r--r-- | include/libssh/ssh2.h | 1 | ||||
-rw-r--r-- | libssh/dh.c | 9 | ||||
-rw-r--r-- | libssh/keys.c | 66 | ||||
-rw-r--r-- | libssh/messages.c | 87 |
6 files changed, 165 insertions, 5 deletions
diff --git a/include/libssh/priv.h b/include/libssh/priv.h index 925d55d2..5d609264 100644 --- a/include/libssh/priv.h +++ b/include/libssh/priv.h @@ -422,6 +422,8 @@ struct ssh_auth_request { char *username; int method; char *password; + struct ssh_public_key_struct *public_key; + char signature_state; }; struct ssh_channel_request_open { @@ -608,6 +610,8 @@ int make_sessionid(SSH_SESSION *session); int hashbufin_add_cookie(SSH_SESSION *session, unsigned char *cookie); int hashbufout_add_cookie(SSH_SESSION *session); int generate_session_keys(SSH_SESSION *session); +int sig_verify(SSH_SESSION *session, ssh_public_key pubkey, + SIGNATURE *signature, unsigned char *digest, int size); /* returns 1 if server signature ok, 0 otherwise. The NEXT crypto is checked, not the current one */ int signature_verify(SSH_SESSION *session,ssh_string signature); bignum make_string_bn(ssh_string string); @@ -659,6 +663,7 @@ ssh_string try_publickey_from_file(SSH_SESSION *session, /* in keys.c */ const char *ssh_type_to_char(int type); int ssh_type_from_name(const char *name); +ssh_buffer ssh_userauth_build_digest(SSH_SESSION *session, struct ssh_message *msg, char *service); ssh_private_key privatekey_make_dss(SSH_SESSION *session, ssh_buffer buffer); ssh_private_key privatekey_make_rsa(SSH_SESSION *session, ssh_buffer buffer, diff --git a/include/libssh/server.h b/include/libssh/server.h index d615d2e6..e441226b 100644 --- a/include/libssh/server.h +++ b/include/libssh/server.h @@ -159,7 +159,9 @@ void ssh_message_free(SSH_MESSAGE *msg); char *ssh_message_auth_user(SSH_MESSAGE *msg); char *ssh_message_auth_password(SSH_MESSAGE *msg); +ssh_public_key ssh_message_auth_publickey(SSH_MESSAGE *msg); int ssh_message_auth_reply_success(SSH_MESSAGE *msg,int partial); +int ssh_message_auth_reply_pk_ok(SSH_MESSAGE *msg, ssh_string algo, ssh_string pubkey); int ssh_message_auth_set_methods(SSH_MESSAGE *msg, int methods); ssh_channel ssh_message_channel_request_open_reply_accept(SSH_MESSAGE *msg); diff --git a/include/libssh/ssh2.h b/include/libssh/ssh2.h index bd89f4e1..f5a1fe52 100644 --- a/include/libssh/ssh2.h +++ b/include/libssh/ssh2.h @@ -26,6 +26,7 @@ #define SSH2_MSG_USERAUTH_PK_OK 60 #define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60 #define SSH2_MSG_USERAUTH_INFO_REQUEST 60 +#define SSH2_MSG_USERAUTH_PK_OK 60 #define SSH2_MSG_USERAUTH_INFO_RESPONSE 61 #define SSH2_MSG_GLOBAL_REQUEST 80 #define SSH2_MSG_REQUEST_SUCCESS 81 diff --git a/libssh/dh.c b/libssh/dh.c index b3512a90..7fc3a5e7 100644 --- a/libssh/dh.c +++ b/libssh/dh.c @@ -891,8 +891,8 @@ static int match(const char *group, const char *object){ return 0; } -static int sig_verify(SSH_SESSION *session, ssh_public_key pubkey, - SIGNATURE *signature, unsigned char *digest) { +int sig_verify(SSH_SESSION *session, ssh_public_key pubkey, + SIGNATURE *signature, unsigned char *digest, int size) { #ifdef HAVE_LIBGCRYPT gcry_error_t valid = 0; gcry_sexp_t gcryhash; @@ -901,7 +901,7 @@ static int sig_verify(SSH_SESSION *session, ssh_public_key pubkey, #endif unsigned char hash[SHA_DIGEST_LEN + 1] = {0}; - sha1(digest,SHA_DIGEST_LEN, hash + 1); + sha1(digest, size, hash + 1); #ifdef DEBUG_CRYPTO ssh_print_hexa("Hash to be verified with dsa", hash + 1, SHA_DIGEST_LEN); @@ -1027,7 +1027,8 @@ int signature_verify(SSH_SESSION *session, ssh_string signature) { ssh_log(session, SSH_LOG_FUNCTIONS, "Going to verify a %s type signature", pubkey->type_c); - err = sig_verify(session,pubkey,sign,session->next_crypto->session_id); + err = sig_verify(session,pubkey,sign, + session->next_crypto->session_id,SHA_DIGEST_LEN); signature_free(sign); session->next_crypto->server_pubkey_type = pubkey->type_c; publickey_free(pubkey); diff --git a/libssh/keys.c b/libssh/keys.c index 402a9538..77d554d8 100644 --- a/libssh/keys.c +++ b/libssh/keys.c @@ -28,6 +28,8 @@ #include <openssl/rsa.h> #endif #include "libssh/priv.h" +#include "libssh/ssh2.h" +#include "libssh/server.h" /** \addtogroup ssh_auth * @{ @@ -1148,6 +1150,70 @@ ssh_string ssh_do_sign_with_agent(ssh_session session, #endif /* _WIN32 */ /* + * This function concats in a buffer the values needed to do a signature + * verification. */ +ssh_buffer ssh_userauth_build_digest(SSH_SESSION *session, struct ssh_message *msg, char *service) { +/* + The value of 'signature' is a signature by the corresponding private + key over the following data, in the following order: + + string session identifier + byte SSH_MSG_USERAUTH_REQUEST + string user name + string service name + string "publickey" + boolean TRUE + string public key algorithm name + string public key to be used for authentication +*/ + CRYPTO *crypto = session->current_crypto ? session->current_crypto : + session->next_crypto; + ssh_buffer buffer = NULL; + ssh_string session_id = NULL; + uint8_t type = SSH2_MSG_USERAUTH_REQUEST; + ssh_string username = string_from_char(msg->auth_request.username); + ssh_string servicename = string_from_char(service); + ssh_string method = string_from_char("publickey"); + uint8_t has_sign = 1; + ssh_string algo = string_from_char(msg->auth_request.public_key->type_c); + ssh_string publickey = publickey_to_string(msg->auth_request.public_key); + + buffer = buffer_new(); + if (buffer == NULL) { + goto error; + } + session_id = string_new(SHA_DIGEST_LEN); + if (session_id == NULL) { + buffer_free(buffer); + buffer = NULL; + goto error; + } + string_fill(session_id, crypto->session_id, SHA_DIGEST_LEN); + + if(buffer_add_ssh_string(buffer, session_id) < 0 || + buffer_add_u8(buffer, type) < 0 || + buffer_add_ssh_string(buffer, username) < 0 || + buffer_add_ssh_string(buffer, servicename) < 0 || + buffer_add_ssh_string(buffer, method) < 0 || + buffer_add_u8(buffer, has_sign) < 0 || + buffer_add_ssh_string(buffer, algo) < 0 || + buffer_add_ssh_string(buffer, publickey) < 0) { + buffer_free(buffer); + buffer = NULL; + goto error; + } + +error: + if(session_id) string_free(session_id); + if(username) string_free(username); + if(servicename) string_free(servicename); + if(method) string_free(method); + if(algo) string_free(algo); + if(publickey) string_free(publickey); + return buffer; +} + +/* * This function signs the session id (known as H) as a string then * the content of sigbuf */ ssh_string ssh_do_sign(SSH_SESSION *session, ssh_buffer sigbuf, diff --git a/libssh/messages.c b/libssh/messages.c index c28a3ce6..284ff72d 100644 --- a/libssh/messages.c +++ b/libssh/messages.c @@ -182,10 +182,10 @@ static SSH_MESSAGE *handle_userauth_request(SSH_SESSION *session){ service_c, method_c, msg->auth_request.username); - SAFE_FREE(service_c); if (strcmp(method_c, "none") == 0) { msg->auth_request.method = SSH_AUTH_NONE; + SAFE_FREE(service_c); SAFE_FREE(method_c); leave_function(); return msg; @@ -196,6 +196,7 @@ static SSH_MESSAGE *handle_userauth_request(SSH_SESSION *session){ uint8_t tmp; msg->auth_request.method = SSH_AUTH_PASSWORD; + SAFE_FREE(service_c); SAFE_FREE(method_c); buffer_get_u8(session->in_buffer, &tmp); pass = buffer_get_ssh_string(session->in_buffer); @@ -211,6 +212,66 @@ static SSH_MESSAGE *handle_userauth_request(SSH_SESSION *session){ return msg; } + if (strcmp(method_c, "publickey") == 0) { + ssh_string algo = NULL; + ssh_string publickey = NULL; + uint8_t has_sign; + + msg->auth_request.method = SSH_AUTH_PUBLICKEY; + SAFE_FREE(method_c); + buffer_get_u8(session->in_buffer, &has_sign); + algo = buffer_get_ssh_string(session->in_buffer); + if (algo == NULL) { + goto error; + } + publickey = buffer_get_ssh_string(session->in_buffer); + if (publickey == NULL) { + string_free(algo); + algo = NULL; + goto error; + } + msg->auth_request.public_key = publickey_from_string(session, publickey); + string_free(algo); + algo = NULL; + string_free(publickey); + publickey = NULL; + if (msg->auth_request.public_key == NULL) { + goto error; + } + msg->auth_request.signature_state = 0; + // has a valid signature ? + if(has_sign) { + SIGNATURE *signature = NULL; + ssh_public_key public_key = msg->auth_request.public_key; + ssh_string sign = NULL; + ssh_buffer digest = NULL; + + sign = buffer_get_ssh_string(session->in_buffer); + if(sign == NULL) { + ssh_log(session, SSH_LOG_PACKET, "Invalid signature packet from peer"); + msg->auth_request.signature_state = -2; + goto error; + } + signature = signature_from_string(session, sign, public_key, + public_key->type); + digest = ssh_userauth_build_digest(session, msg, service_c); + if(sig_verify(session, public_key, signature, + buffer_get(digest), buffer_get_len(digest)) < 0) { + ssh_log(session, SSH_LOG_PACKET, "Invalid signature from peer"); + msg->auth_request.signature_state = -1; + string_free(sign); + sign = NULL; + goto error; + } + else + ssh_log(session, SSH_LOG_PACKET, "Valid signature received"); + msg->auth_request.signature_state = 1; + } + SAFE_FREE(service_c); + leave_function(); + return msg; + } + msg->auth_request.method = SSH_AUTH_UNKNOWN; SAFE_FREE(method_c); @@ -246,6 +307,15 @@ char *ssh_message_auth_password(SSH_MESSAGE *msg){ return msg->auth_request.password; } +/* Get the publickey of an auth request */ +ssh_public_key ssh_message_auth_publickey(SSH_MESSAGE *msg){ + if (msg == NULL) { + return NULL; + } + + return msg->auth_request.public_key; +} + int ssh_message_auth_set_methods(SSH_MESSAGE *msg, int methods) { if (msg == NULL || msg->session == NULL) { return -1; @@ -333,6 +403,21 @@ int ssh_message_auth_reply_success(SSH_MESSAGE *msg, int partial) { return packet_send(msg->session); } +/* Answer OK to a pubkey auth request */ +int ssh_message_auth_reply_pk_ok(SSH_MESSAGE *msg, ssh_string algo, ssh_string pubkey) { + if (msg == NULL) { + return SSH_ERROR; + } + + if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_USERAUTH_PK_OK) < 0 || + buffer_add_ssh_string(msg->session->out_buffer, algo) < 0 || + buffer_add_ssh_string(msg->session->out_buffer, pubkey) < 0) { + return SSH_ERROR; + } + + return packet_send(msg->session); +} + static SSH_MESSAGE *handle_channel_request_open(SSH_SESSION *session) { SSH_MESSAGE *msg = NULL; ssh_string type = NULL; |