aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormilo <milo.sshiva@gmail.com>2009-07-27 17:59:02 +0200
committerAndreas Schneider <mail@cynapses.org>2009-07-27 20:27:07 +0200
commite8f7801540e8be8b029b09269196773767a5983e (patch)
tree8cc08e3cbcc4e919f132fae4a5cde91bea8e7e94
parentcdde79418a86da1c9579a022ec8c4ed73fe29f1a (diff)
downloadlibssh-e8f7801540e8be8b029b09269196773767a5983e.tar.gz
libssh-e8f7801540e8be8b029b09269196773767a5983e.tar.xz
libssh-e8f7801540e8be8b029b09269196773767a5983e.zip
Public key authentication server side
-rw-r--r--include/libssh/priv.h5
-rw-r--r--include/libssh/server.h2
-rw-r--r--include/libssh/ssh2.h1
-rw-r--r--libssh/dh.c9
-rw-r--r--libssh/keys.c66
-rw-r--r--libssh/messages.c87
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;