mirror of
https://git.libssh.org/projects/libssh.git
synced 2025-12-17 06:18:58 +03:00
Public key authentication server side
This commit is contained in:
@@ -422,6 +422,8 @@ struct ssh_auth_request {
|
|||||||
char *username;
|
char *username;
|
||||||
int method;
|
int method;
|
||||||
char *password;
|
char *password;
|
||||||
|
struct ssh_public_key_struct *public_key;
|
||||||
|
char signature_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ssh_channel_request_open {
|
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 hashbufin_add_cookie(SSH_SESSION *session, unsigned char *cookie);
|
||||||
int hashbufout_add_cookie(SSH_SESSION *session);
|
int hashbufout_add_cookie(SSH_SESSION *session);
|
||||||
int generate_session_keys(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 */
|
/* 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);
|
int signature_verify(SSH_SESSION *session,ssh_string signature);
|
||||||
bignum make_string_bn(ssh_string string);
|
bignum make_string_bn(ssh_string string);
|
||||||
@@ -659,6 +663,7 @@ ssh_string try_publickey_from_file(SSH_SESSION *session,
|
|||||||
/* in keys.c */
|
/* in keys.c */
|
||||||
const char *ssh_type_to_char(int type);
|
const char *ssh_type_to_char(int type);
|
||||||
int ssh_type_from_name(const char *name);
|
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_dss(SSH_SESSION *session, ssh_buffer buffer);
|
||||||
ssh_private_key privatekey_make_rsa(SSH_SESSION *session, ssh_buffer buffer,
|
ssh_private_key privatekey_make_rsa(SSH_SESSION *session, ssh_buffer buffer,
|
||||||
|
|||||||
@@ -159,7 +159,9 @@ void ssh_message_free(SSH_MESSAGE *msg);
|
|||||||
|
|
||||||
char *ssh_message_auth_user(SSH_MESSAGE *msg);
|
char *ssh_message_auth_user(SSH_MESSAGE *msg);
|
||||||
char *ssh_message_auth_password(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_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);
|
int ssh_message_auth_set_methods(SSH_MESSAGE *msg, int methods);
|
||||||
|
|
||||||
ssh_channel ssh_message_channel_request_open_reply_accept(SSH_MESSAGE *msg);
|
ssh_channel ssh_message_channel_request_open_reply_accept(SSH_MESSAGE *msg);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#define SSH2_MSG_USERAUTH_PK_OK 60
|
#define SSH2_MSG_USERAUTH_PK_OK 60
|
||||||
#define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60
|
#define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60
|
||||||
#define SSH2_MSG_USERAUTH_INFO_REQUEST 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_USERAUTH_INFO_RESPONSE 61
|
||||||
#define SSH2_MSG_GLOBAL_REQUEST 80
|
#define SSH2_MSG_GLOBAL_REQUEST 80
|
||||||
#define SSH2_MSG_REQUEST_SUCCESS 81
|
#define SSH2_MSG_REQUEST_SUCCESS 81
|
||||||
|
|||||||
@@ -891,8 +891,8 @@ static int match(const char *group, const char *object){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sig_verify(SSH_SESSION *session, ssh_public_key pubkey,
|
int sig_verify(SSH_SESSION *session, ssh_public_key pubkey,
|
||||||
SIGNATURE *signature, unsigned char *digest) {
|
SIGNATURE *signature, unsigned char *digest, int size) {
|
||||||
#ifdef HAVE_LIBGCRYPT
|
#ifdef HAVE_LIBGCRYPT
|
||||||
gcry_error_t valid = 0;
|
gcry_error_t valid = 0;
|
||||||
gcry_sexp_t gcryhash;
|
gcry_sexp_t gcryhash;
|
||||||
@@ -901,7 +901,7 @@ static int sig_verify(SSH_SESSION *session, ssh_public_key pubkey,
|
|||||||
#endif
|
#endif
|
||||||
unsigned char hash[SHA_DIGEST_LEN + 1] = {0};
|
unsigned char hash[SHA_DIGEST_LEN + 1] = {0};
|
||||||
|
|
||||||
sha1(digest,SHA_DIGEST_LEN, hash + 1);
|
sha1(digest, size, hash + 1);
|
||||||
|
|
||||||
#ifdef DEBUG_CRYPTO
|
#ifdef DEBUG_CRYPTO
|
||||||
ssh_print_hexa("Hash to be verified with dsa", hash + 1, SHA_DIGEST_LEN);
|
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,
|
ssh_log(session, SSH_LOG_FUNCTIONS,
|
||||||
"Going to verify a %s type signature", pubkey->type_c);
|
"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);
|
signature_free(sign);
|
||||||
session->next_crypto->server_pubkey_type = pubkey->type_c;
|
session->next_crypto->server_pubkey_type = pubkey->type_c;
|
||||||
publickey_free(pubkey);
|
publickey_free(pubkey);
|
||||||
|
|||||||
@@ -28,6 +28,8 @@
|
|||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
#endif
|
#endif
|
||||||
#include "libssh/priv.h"
|
#include "libssh/priv.h"
|
||||||
|
#include "libssh/ssh2.h"
|
||||||
|
#include "libssh/server.h"
|
||||||
|
|
||||||
/** \addtogroup ssh_auth
|
/** \addtogroup ssh_auth
|
||||||
* @{
|
* @{
|
||||||
@@ -1147,6 +1149,70 @@ ssh_string ssh_do_sign_with_agent(ssh_session session,
|
|||||||
}
|
}
|
||||||
#endif /* _WIN32 */
|
#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
|
* This function signs the session id (known as H) as a string then
|
||||||
* the content of sigbuf */
|
* the content of sigbuf */
|
||||||
|
|||||||
@@ -182,10 +182,10 @@ static SSH_MESSAGE *handle_userauth_request(SSH_SESSION *session){
|
|||||||
service_c, method_c,
|
service_c, method_c,
|
||||||
msg->auth_request.username);
|
msg->auth_request.username);
|
||||||
|
|
||||||
SAFE_FREE(service_c);
|
|
||||||
|
|
||||||
if (strcmp(method_c, "none") == 0) {
|
if (strcmp(method_c, "none") == 0) {
|
||||||
msg->auth_request.method = SSH_AUTH_NONE;
|
msg->auth_request.method = SSH_AUTH_NONE;
|
||||||
|
SAFE_FREE(service_c);
|
||||||
SAFE_FREE(method_c);
|
SAFE_FREE(method_c);
|
||||||
leave_function();
|
leave_function();
|
||||||
return msg;
|
return msg;
|
||||||
@@ -196,6 +196,7 @@ static SSH_MESSAGE *handle_userauth_request(SSH_SESSION *session){
|
|||||||
uint8_t tmp;
|
uint8_t tmp;
|
||||||
|
|
||||||
msg->auth_request.method = SSH_AUTH_PASSWORD;
|
msg->auth_request.method = SSH_AUTH_PASSWORD;
|
||||||
|
SAFE_FREE(service_c);
|
||||||
SAFE_FREE(method_c);
|
SAFE_FREE(method_c);
|
||||||
buffer_get_u8(session->in_buffer, &tmp);
|
buffer_get_u8(session->in_buffer, &tmp);
|
||||||
pass = buffer_get_ssh_string(session->in_buffer);
|
pass = buffer_get_ssh_string(session->in_buffer);
|
||||||
@@ -211,6 +212,66 @@ static SSH_MESSAGE *handle_userauth_request(SSH_SESSION *session){
|
|||||||
return msg;
|
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;
|
msg->auth_request.method = SSH_AUTH_UNKNOWN;
|
||||||
SAFE_FREE(method_c);
|
SAFE_FREE(method_c);
|
||||||
|
|
||||||
@@ -246,6 +307,15 @@ char *ssh_message_auth_password(SSH_MESSAGE *msg){
|
|||||||
return msg->auth_request.password;
|
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) {
|
int ssh_message_auth_set_methods(SSH_MESSAGE *msg, int methods) {
|
||||||
if (msg == NULL || msg->session == NULL) {
|
if (msg == NULL || msg->session == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -333,6 +403,21 @@ int ssh_message_auth_reply_success(SSH_MESSAGE *msg, int partial) {
|
|||||||
return packet_send(msg->session);
|
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) {
|
static SSH_MESSAGE *handle_channel_request_open(SSH_SESSION *session) {
|
||||||
SSH_MESSAGE *msg = NULL;
|
SSH_MESSAGE *msg = NULL;
|
||||||
ssh_string type = NULL;
|
ssh_string type = NULL;
|
||||||
|
|||||||
Reference in New Issue
Block a user