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;
|
||||
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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include <openssl/rsa.h>
|
||||
#endif
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/server.h"
|
||||
|
||||
/** \addtogroup ssh_auth
|
||||
* @{
|
||||
@@ -1147,6 +1149,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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user