server kex done :)
git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@6 7dcaeef0-15fb-0310-b436-a5af3365683c
Этот коммит содержится в:
родитель
3113d87566
Коммит
5c26ae7354
4
Doxyfile
4
Doxyfile
@ -25,7 +25,7 @@ ABBREVIATE_BRIEF = "The $name class" \
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = YES
|
||||
STRIP_FROM_PATH = /home/aris/
|
||||
STRIP_FROM_PATH = /home/aris/dev/libssh-0.2-dev/svn/trunk/
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
@ -77,7 +77,7 @@ WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = /home/aris/dev/libssh-dev
|
||||
INPUT = /home/aris/dev/libssh-0.2-dev/svn/trunk
|
||||
FILE_PATTERNS = *.c \
|
||||
*.cc \
|
||||
*.cxx \
|
||||
|
@ -103,10 +103,12 @@ void ssh_set_verbosity(int num);
|
||||
/* 0 : important messages only */
|
||||
/* -1 : no messages */
|
||||
|
||||
/* in client.c */
|
||||
|
||||
/* session.c */
|
||||
SSH_SESSION *ssh_new();
|
||||
void ssh_set_options(SSH_SESSION *session, SSH_OPTIONS *options);
|
||||
int ssh_get_fd(SSH_SESSION *session);
|
||||
|
||||
/* client.c */
|
||||
int ssh_connect();
|
||||
void ssh_disconnect(SSH_SESSION *session);
|
||||
int ssh_service_request(SSH_SESSION *session,char *service);
|
||||
@ -134,15 +136,12 @@ void ssh_crypto_init();
|
||||
|
||||
/* useful for debug */
|
||||
void ssh_print_hexa(char *descr,unsigned char *what, int len);
|
||||
void ssh_get_random(void *,int);
|
||||
int ssh_get_random(void *where,int len,int strong);
|
||||
|
||||
/* this one can be called by the client to see the hash of the public key before accepting it */
|
||||
int ssh_get_pubkey_hash(SSH_SESSION *session,char hash[MD5_DIGEST_LEN]);
|
||||
STRING *ssh_get_pubkey(SSH_SESSION *session);
|
||||
|
||||
/* deprecated */
|
||||
int pubkey_get_hash(SSH_SESSION *session,char hash[MD5_DIGEST_LEN]);
|
||||
|
||||
/* in connect.c */
|
||||
int ssh_fd_poll(SSH_SESSION *session);
|
||||
int ssh_select(CHANNEL **channels,CHANNEL **outchannels, int maxfd, fd_set *readfds, struct timeval *timeout);
|
||||
@ -152,6 +151,8 @@ void publickey_free(PUBLIC_KEY *key);
|
||||
/* in keyfiles.c */
|
||||
|
||||
PRIVATE_KEY *privatekey_from_file(SSH_SESSION *session,char *filename,int type,char *passphrase);
|
||||
STRING *publickey_to_string(PUBLIC_KEY *key);
|
||||
PUBLIC_KEY *publickey_from_privatekey(PRIVATE_KEY *prv);
|
||||
void private_key_free(PRIVATE_KEY *prv);
|
||||
STRING *publickey_from_file(SSH_SESSION *session, char *filename,int *_type);
|
||||
STRING *publickey_from_next_file(SSH_SESSION *session,char **pub_keys_path,char **keys_path,
|
||||
|
@ -177,10 +177,12 @@ struct ssh_options_struct {
|
||||
long timeout_usec;
|
||||
int ssh2allowed;
|
||||
int ssh1allowed;
|
||||
char *dsakey;
|
||||
char *rsakey; /* host key for server implementation */
|
||||
};
|
||||
|
||||
typedef struct ssh_crypto_struct {
|
||||
bignum e,f,x,k;
|
||||
bignum e,f,x,k,y;
|
||||
char session_id[SHA_DIGEST_LEN];
|
||||
|
||||
char encryptIV[SHA_DIGEST_LEN*2];
|
||||
@ -286,6 +288,10 @@ struct ssh_session {
|
||||
/* keyb interactive data */
|
||||
struct ssh_kbdint *kbdint;
|
||||
int version; /* 1 or 2 */
|
||||
/* server host keys */
|
||||
PRIVATE_KEY *rsa_key;
|
||||
PRIVATE_KEY *dsa_key;
|
||||
int hostkeys; /* contains type of host key wanted by client, in server impl */
|
||||
};
|
||||
|
||||
struct ssh_kbdint {
|
||||
@ -303,6 +309,7 @@ void ssh_cleanup(SSH_SESSION *session);
|
||||
/* client.c */
|
||||
|
||||
int ssh_send_banner(SSH_SESSION *session, int is_server);
|
||||
char *ssh_get_banner(SSH_SESSION *session);
|
||||
|
||||
/* errors.c */
|
||||
void ssh_set_error(void *error,int code,char *descr,...);
|
||||
@ -311,8 +318,13 @@ void ssh_set_error(void *error,int code,char *descr,...);
|
||||
/* DH key generation */
|
||||
void dh_generate_e(SSH_SESSION *session);
|
||||
void dh_generate_x(SSH_SESSION *session);
|
||||
void dh_generate_y(SSH_SESSION *session);
|
||||
void dh_generate_f(SSH_SESSION *session);
|
||||
|
||||
STRING *dh_get_e(SSH_SESSION *session);
|
||||
STRING *dh_get_f(SSH_SESSION *session);
|
||||
void dh_import_f(SSH_SESSION *session,STRING *f_string);
|
||||
void dh_import_e(SSH_SESSION *session, STRING *e_string);
|
||||
void dh_import_pubkey(SSH_SESSION *session,STRING *pubkey_string);
|
||||
void dh_build_k(SSH_SESSION *session);
|
||||
void make_sessionid(SSH_SESSION *session);
|
||||
@ -348,13 +360,18 @@ int ssh_connect_host(SSH_SESSION *session, const char *host,const char
|
||||
|
||||
/* in kex.c */
|
||||
extern char *ssh_kex_nums[];
|
||||
void send_kex(SSH_SESSION *session,int server_kex);
|
||||
void list_kex(KEX *kex);
|
||||
void ssh_send_kex(SSH_SESSION *session,int server_kex);
|
||||
void ssh_list_kex(KEX *kex);
|
||||
int set_kex(SSH_SESSION *session);
|
||||
int ssh_get_kex(SSH_SESSION *session, int server_kex);
|
||||
int verify_existing_algo(int algo,char *name);
|
||||
char **space_tokenize(char *chain);
|
||||
int ssh_get_kex1(SSH_SESSION *session);
|
||||
char *ssh_find_matching(char *in_d, char *what_d);
|
||||
|
||||
/* in keyfiles.c */
|
||||
|
||||
PRIVATE_KEY *_privatekey_from_file(void *session,char *filename,int type);
|
||||
|
||||
/* in keys.c */
|
||||
char *ssh_type_to_char(int type);
|
||||
@ -365,6 +382,7 @@ SIGNATURE *signature_from_string(STRING *signature,PUBLIC_KEY *pubkey,int needed
|
||||
void signature_free(SIGNATURE *sign);
|
||||
STRING *ssh_do_sign(SSH_SESSION *session,BUFFER *sigbuf,
|
||||
PRIVATE_KEY *privatekey);
|
||||
STRING *ssh_sign_session_id(SSH_SESSION *session, PRIVATE_KEY *privatekey);
|
||||
STRING *ssh_encrypt_rsa1(SSH_SESSION *session, STRING *data, PUBLIC_KEY *key);
|
||||
/* channel.c */
|
||||
void channel_handle(SSH_SESSION *session, int type);
|
||||
@ -420,6 +438,7 @@ int decompress_buffer(SSH_SESSION *session,BUFFER *buf);
|
||||
|
||||
/* wrapper.c */
|
||||
int crypt_set_algorithms(SSH_SESSION *);
|
||||
int crypt_set_algorithms_server(SSH_SESSION *session);
|
||||
CRYPTO *crypto_new();
|
||||
void crypto_free(CRYPTO *crypto);
|
||||
bignum bignum_new();
|
||||
|
@ -43,5 +43,23 @@ int ssh_bind_get_fd(SSH_BIND *ssh_bind);
|
||||
int ssh_bind_set_toaccept(SSH_BIND *ssh_bind);
|
||||
SSH_SESSION *ssh_bind_accept(SSH_BIND *ssh_bind);
|
||||
|
||||
int ssh_accept(SSH_SESSION *session);
|
||||
|
||||
/* messages.c */
|
||||
|
||||
struct ssh_auth_request {
|
||||
char *username;
|
||||
int method;
|
||||
char *password;
|
||||
};
|
||||
|
||||
struct ssh_message {
|
||||
int type;
|
||||
struct ssh_auth_request auth_request;
|
||||
};
|
||||
|
||||
typedef struct ssh_message SSH_MESSAGE;
|
||||
|
||||
SSH_MESSAGE *ssh_message_get(SSH_SESSION *session);
|
||||
|
||||
#endif
|
||||
|
@ -11,7 +11,7 @@
|
||||
#define SSH2_MSG_KEXINIT 20
|
||||
#define SSH2_MSG_NEWKEYS 21
|
||||
|
||||
#define SSH2_MSG_KEXDH_INIT 30
|
||||
#define SSH2_MSG_KEXDH_INIT 30
|
||||
#define SSH2_MSG_KEXDH_REPLY 31
|
||||
|
||||
#define SSH2_MSG_KEX_DH_GEX_REQUEST_OLD 30
|
||||
|
@ -2,7 +2,7 @@
|
||||
OBJECTS= client.o packet.o dh.o crypt.o connect.o error.o buffer.o \
|
||||
string.o kex.o channels.o options.o keys.o auth.o base64.o \
|
||||
keyfiles.o misc.o gzip.o wrapper.o sftp.o server.o crc32.o \
|
||||
session.o
|
||||
session.o messages.o
|
||||
SHELL = /bin/sh
|
||||
VPATH = @srcdir@
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* auth.c deals with authentication methods */
|
||||
/*
|
||||
Copyright 2003 Aris Adamantiadis
|
||||
Copyright 2003-2005 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* base64 contains the needed support for base64 alphabet system, */
|
||||
/* as described in RFC1521 */
|
||||
/*
|
||||
Copyright 2003,04 Aris Adamantiadis
|
||||
Copyright 2003-2005 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
|
@ -104,7 +104,7 @@ int ssh_send_banner(SSH_SESSION *session,int server){
|
||||
}
|
||||
|
||||
|
||||
int dh_handshake(SSH_SESSION *session){
|
||||
static int dh_handshake(SSH_SESSION *session){
|
||||
STRING *e,*f,*pubkey,*signature;
|
||||
packet_clear_out(session);
|
||||
buffer_add_u8(session->out_buffer,SSH2_MSG_KEXDH_INIT);
|
||||
@ -186,6 +186,7 @@ int ssh_connect(SSH_SESSION *session){
|
||||
ssh_set_error(session,SSH_FATAL,"Must set options before connect");
|
||||
return -1;
|
||||
}
|
||||
session->client=1;
|
||||
ssh_crypto_init();
|
||||
if(options->fd==-1 && !options->host){
|
||||
ssh_set_error(session,SSH_FATAL,"Hostname required");
|
||||
@ -222,7 +223,6 @@ int ssh_connect(SSH_SESSION *session){
|
||||
ssh_set_error(session,SSH_FATAL,
|
||||
"no version of SSH protocol usable (banner: %s)",
|
||||
session->serverbanner);
|
||||
ssh_disconnect(session);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -231,19 +231,16 @@ int ssh_connect(SSH_SESSION *session){
|
||||
switch(session->version){
|
||||
case 2:
|
||||
if(ssh_get_kex(session,0)){
|
||||
ssh_disconnect(session);
|
||||
return -1;
|
||||
}
|
||||
set_status(options,0.6);
|
||||
list_kex(&session->server_kex);
|
||||
ssh_list_kex(&session->server_kex);
|
||||
if(set_kex(session)){
|
||||
ssh_disconnect(session);
|
||||
return -1;
|
||||
}
|
||||
send_kex(session,0);
|
||||
ssh_send_kex(session,0);
|
||||
set_status(options,0.8);
|
||||
if(dh_handshake(session)){
|
||||
ssh_disconnect(session);
|
||||
return -1;
|
||||
}
|
||||
set_status(options,1.0);
|
||||
@ -251,7 +248,6 @@ int ssh_connect(SSH_SESSION *session){
|
||||
break;
|
||||
case 1:
|
||||
if(ssh_get_kex1(session)){
|
||||
ssh_disconnect(session);
|
||||
return -1;
|
||||
}
|
||||
set_status(options,0.6);
|
||||
|
199
libssh/dh.c
199
libssh/dh.c
@ -67,16 +67,12 @@ static bignum p;
|
||||
|
||||
/* maybe it might be enhanced .... */
|
||||
/* XXX Do it. */
|
||||
void ssh_get_random(void *where, int len){
|
||||
static int rndfd=0;
|
||||
if(!rndfd){
|
||||
rndfd=open("/dev/urandom",O_RDONLY);
|
||||
if(rndfd<0){
|
||||
fprintf(stderr,"Can't open /dev/urandom\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
read(rndfd,where,len);
|
||||
int ssh_get_random(void *where, int len, int strong){
|
||||
if(strong){
|
||||
return RAND_bytes(where,len);
|
||||
} else {
|
||||
return RAND_pseudo_bytes(where,len);
|
||||
}
|
||||
}
|
||||
|
||||
/* it inits the values g and p which are used for DH key agreement */
|
||||
@ -101,11 +97,16 @@ void ssh_print_bignum(char *which,bignum num){
|
||||
}
|
||||
|
||||
void ssh_print_hexa(char *descr,unsigned char *what, int len){
|
||||
int i;
|
||||
printf("%s : ",descr);
|
||||
for(i=0;i<len-1;i++)
|
||||
printf("%.2hhx:",what[i]);
|
||||
printf("%.2hhx\n",what[i]);
|
||||
int i;
|
||||
printf("%s : ",descr);
|
||||
if(len>16)
|
||||
printf ("\n ");
|
||||
for(i=0;i<len-1;i++){
|
||||
printf("%.2hhx:",what[i]);
|
||||
if((i+1) % 16 ==0)
|
||||
printf("\n ");
|
||||
}
|
||||
printf("%.2hhx\n",what[i]);
|
||||
}
|
||||
|
||||
void dh_generate_x(SSH_SESSION *session){
|
||||
@ -116,7 +117,16 @@ void dh_generate_x(SSH_SESSION *session){
|
||||
ssh_print_bignum("x",session->next_crypto->x);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* used by server */
|
||||
void dh_generate_y(SSH_SESSION *session){
|
||||
session->next_crypto->y=bignum_new();
|
||||
bignum_rand(session->next_crypto->y,128,0,-1);
|
||||
/* not harder than this */
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_bignum("y",session->next_crypto->y);
|
||||
#endif
|
||||
}
|
||||
/* used by server */
|
||||
void dh_generate_e(SSH_SESSION *session){
|
||||
bignum_CTX ctx=bignum_ctx_new();
|
||||
session->next_crypto->e=bignum_new();
|
||||
@ -127,6 +137,15 @@ void dh_generate_e(SSH_SESSION *session){
|
||||
bignum_ctx_free(ctx);
|
||||
}
|
||||
|
||||
void dh_generate_f(SSH_SESSION *session){
|
||||
bignum_CTX ctx=bignum_ctx_new();
|
||||
session->next_crypto->f=bignum_new();
|
||||
bignum_mod_exp(session->next_crypto->f,g,session->next_crypto->y,p,ctx);
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_bignum("f",session->next_crypto->f);
|
||||
#endif
|
||||
bignum_ctx_free(ctx);
|
||||
}
|
||||
|
||||
STRING *make_bignum_string(bignum num){
|
||||
STRING *ptr;
|
||||
@ -156,6 +175,11 @@ STRING *dh_get_e(SSH_SESSION *session){
|
||||
return make_bignum_string(session->next_crypto->e);
|
||||
}
|
||||
|
||||
/* used by server */
|
||||
|
||||
STRING *dh_get_f(SSH_SESSION *session){
|
||||
return make_bignum_string(session->next_crypto->f);
|
||||
}
|
||||
void dh_import_pubkey(SSH_SESSION *session,STRING *pubkey_string){
|
||||
session->next_crypto->server_pubkey=pubkey_string;
|
||||
}
|
||||
@ -167,10 +191,23 @@ void dh_import_f(SSH_SESSION *session,STRING *f_string){
|
||||
#endif
|
||||
}
|
||||
|
||||
/* used by the server implementation */
|
||||
void dh_import_e(SSH_SESSION *session, STRING *e_string){
|
||||
session->next_crypto->e=make_string_bn(e_string);
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_bignum("e",session->next_crypto->e);
|
||||
#endif
|
||||
}
|
||||
|
||||
void dh_build_k(SSH_SESSION *session){
|
||||
bignum_CTX ctx=bignum_ctx_new();
|
||||
session->next_crypto->k=bignum_new();
|
||||
bignum_mod_exp(session->next_crypto->k,session->next_crypto->f,session->next_crypto->x,p,ctx);
|
||||
/* the server and clients don't use the same numbers */
|
||||
if(session->client){
|
||||
bignum_mod_exp(session->next_crypto->k,session->next_crypto->f,session->next_crypto->x,p,ctx);
|
||||
} else {
|
||||
bignum_mod_exp(session->next_crypto->k,session->next_crypto->e,session->next_crypto->y,p,ctx);
|
||||
}
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_bignum("shared secret key",session->next_crypto->k);
|
||||
#endif
|
||||
@ -179,62 +216,95 @@ void dh_build_k(SSH_SESSION *session){
|
||||
|
||||
static void sha_add(STRING *str,SHACTX *ctx){
|
||||
sha1_update(ctx,str,string_len(str)+4);
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("partial hashed sessionid",str,string_len(str)+4);
|
||||
#endif
|
||||
}
|
||||
|
||||
void make_sessionid(SSH_SESSION *session){
|
||||
SHACTX *ctx;
|
||||
STRING *num,*str;
|
||||
int len;
|
||||
BUFFER *server_hash, *client_hash;
|
||||
BUFFER *buf=buffer_new();
|
||||
u32 len;
|
||||
ctx=sha1_init();
|
||||
|
||||
str=string_from_char(session->clientbanner);
|
||||
sha_add(str,ctx);
|
||||
buffer_add_ssh_string(buf,str);
|
||||
//sha_add(str,ctx);
|
||||
free(str);
|
||||
|
||||
str=string_from_char(session->serverbanner);
|
||||
sha_add(str,ctx);
|
||||
buffer_add_ssh_string(buf,str);
|
||||
//sha_add(str,ctx);
|
||||
free(str);
|
||||
if(session->client){
|
||||
server_hash=session->in_hashbuf;
|
||||
client_hash=session->out_hashbuf;
|
||||
} else{
|
||||
server_hash=session->out_hashbuf;
|
||||
client_hash=session->in_hashbuf;
|
||||
}
|
||||
buffer_add_u32(server_hash,0);
|
||||
buffer_add_u8(server_hash,0);
|
||||
buffer_add_u32(client_hash,0);
|
||||
buffer_add_u8(client_hash,0);
|
||||
|
||||
buffer_add_u32(session->in_hashbuf,0);
|
||||
buffer_add_u8(session->in_hashbuf,0);
|
||||
buffer_add_u32(session->out_hashbuf,0);
|
||||
buffer_add_u8(session->out_hashbuf,0);
|
||||
len=ntohl(buffer_get_len(client_hash));
|
||||
//sha1_update(ctx,&len,4);
|
||||
buffer_add_u32(buf,len);
|
||||
buffer_add_data(buf,buffer_get(client_hash),buffer_get_len(client_hash));
|
||||
//sha1_update(ctx,buffer_get(client_hash),buffer_get_len(client_hash));
|
||||
buffer_free(client_hash);
|
||||
|
||||
len=ntohl(buffer_get_len(session->out_hashbuf));
|
||||
sha1_update(ctx,&len,4);
|
||||
len=ntohl(buffer_get_len(server_hash));
|
||||
buffer_add_u32(buf,len);
|
||||
//sha1_update(ctx,&len,4);
|
||||
|
||||
sha1_update(ctx,buffer_get(session->out_hashbuf),buffer_get_len(session->out_hashbuf));
|
||||
buffer_free(session->out_hashbuf);
|
||||
session->out_hashbuf=NULL;
|
||||
|
||||
len=ntohl(buffer_get_len(session->in_hashbuf));
|
||||
sha1_update(ctx,&len,4);
|
||||
|
||||
sha1_update(ctx,buffer_get(session->in_hashbuf),buffer_get_len(session->in_hashbuf));
|
||||
buffer_free(session->in_hashbuf);
|
||||
buffer_add_data(buf,buffer_get(server_hash),buffer_get_len(server_hash));
|
||||
// ssh_print_hexa("server_hash",buffer_get(server_hash),buffer_get_len(server_hash));
|
||||
//sha1_update(ctx,buffer_get(server_hash),buffer_get_len(server_hash));
|
||||
buffer_free(server_hash);
|
||||
|
||||
session->in_hashbuf=NULL;
|
||||
sha1_update(ctx,session->next_crypto->server_pubkey,len=(string_len(session->next_crypto->server_pubkey)+4));
|
||||
session->out_hashbuf=NULL;
|
||||
len=string_len(session->next_crypto->server_pubkey)+4;
|
||||
buffer_add_data(buf,session->next_crypto->server_pubkey,len);
|
||||
// sha1_update(ctx,session->next_crypto->server_pubkey,len);
|
||||
num=make_bignum_string(session->next_crypto->e);
|
||||
sha1_update(ctx,num,len=(string_len(num)+4));
|
||||
len=string_len(num)+4;
|
||||
buffer_add_data(buf,num,len);
|
||||
//sha1_update(ctx,num,len);
|
||||
free(num);
|
||||
num=make_bignum_string(session->next_crypto->f);
|
||||
sha1_update(ctx,num,len=(string_len(num)+4));
|
||||
len=string_len(num)+4;
|
||||
buffer_add_data(buf,num,len);
|
||||
// sha1_update(ctx,num,len=(string_len(num)+4));
|
||||
free(num);
|
||||
num=make_bignum_string(session->next_crypto->k);
|
||||
sha1_update(ctx,num,len=(string_len(num)+4));
|
||||
len=string_len(num)+4;
|
||||
buffer_add_data(buf,num,len);
|
||||
// sha1_update(ctx,num,len);
|
||||
free(num);
|
||||
sha1_final(session->next_crypto->session_id,ctx);
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
printf("Session hash : ");
|
||||
ssh_print_hexa("session id",session->next_crypto->session_id,SHA_DIGEST_LENGTH);
|
||||
ssh_print_hexa("hash buffer",buffer_get(buf),buffer_get_len(buf));
|
||||
#endif
|
||||
sha1_update(ctx,buffer_get(buf),buffer_get_len(buf));
|
||||
sha1_final(session->next_crypto->session_id,ctx);
|
||||
buffer_free(buf);
|
||||
#ifdef DEBUG_CRYPTO
|
||||
printf("Session hash : ");
|
||||
ssh_print_hexa("session id",session->next_crypto->session_id,SHA_DIGEST_LENGTH);
|
||||
#endif
|
||||
}
|
||||
|
||||
void hashbufout_add_cookie(SSH_SESSION *session){
|
||||
session->out_hashbuf=buffer_new();
|
||||
buffer_add_u8(session->out_hashbuf,20);
|
||||
buffer_add_data(session->out_hashbuf,session->client_kex.cookie,16);
|
||||
if(session->server)
|
||||
buffer_add_data(session->out_hashbuf,session->server_kex.cookie,16);
|
||||
else
|
||||
buffer_add_data(session->out_hashbuf,session->client_kex.cookie,16);
|
||||
}
|
||||
|
||||
|
||||
@ -259,12 +329,22 @@ void generate_session_keys(SSH_SESSION *session){
|
||||
k_string=make_bignum_string(session->next_crypto->k);
|
||||
|
||||
/* IV */
|
||||
generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->encryptIV,'A');
|
||||
generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->decryptIV,'B');
|
||||
|
||||
generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->encryptkey,'C');
|
||||
|
||||
if(session->client){
|
||||
generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->encryptIV,'A');
|
||||
generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->decryptIV,'B');
|
||||
} else {
|
||||
generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->decryptIV,'A');
|
||||
generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->encryptIV,'B');
|
||||
}
|
||||
if(session->client){
|
||||
generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->encryptkey,'C');
|
||||
generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->decryptkey,'D');
|
||||
} else {
|
||||
generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->decryptkey,'C');
|
||||
generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->encryptkey,'D');
|
||||
}
|
||||
/* some ciphers need more than 20 bytes of input key */
|
||||
/* XXX verify it's ok for server implementation */
|
||||
if(session->next_crypto->out_cipher->keylen > SHA_DIGEST_LENGTH*8){
|
||||
ctx=sha1_init();
|
||||
sha1_update(ctx,k_string,string_len(k_string)+4);
|
||||
@ -273,8 +353,6 @@ void generate_session_keys(SSH_SESSION *session){
|
||||
sha1_final(session->next_crypto->encryptkey+SHA_DIGEST_LEN,ctx);
|
||||
}
|
||||
|
||||
generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->decryptkey,'D');
|
||||
|
||||
if(session->next_crypto->in_cipher->keylen > SHA_DIGEST_LENGTH*8){
|
||||
ctx=sha1_init();
|
||||
sha1_update(ctx,k_string,string_len(k_string)+4);
|
||||
@ -282,13 +360,17 @@ void generate_session_keys(SSH_SESSION *session){
|
||||
sha1_update(ctx,session->next_crypto->decryptkey,SHA_DIGEST_LENGTH);
|
||||
sha1_final(session->next_crypto->decryptkey+SHA_DIGEST_LEN,ctx);
|
||||
}
|
||||
|
||||
generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->encryptMAC,'E');
|
||||
generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->decryptMAC,'F');
|
||||
if(session->client){
|
||||
generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->encryptMAC,'E');
|
||||
generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->decryptMAC,'F');
|
||||
} else {
|
||||
generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->decryptMAC,'E');
|
||||
generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->encryptMAC,'F');
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("client->server IV",session->next_crypto->encryptIV,SHA_DIGEST_LENGTH);
|
||||
ssh_print_hexa("server->client IV",session->next_crypto->decryptIV,SHA_DIGEST_LENGTH);
|
||||
ssh_print_hexa("encrypt IV",session->next_crypto->encryptIV,SHA_DIGEST_LENGTH);
|
||||
ssh_print_hexa("decrypt IV",session->next_crypto->decryptIV,SHA_DIGEST_LENGTH);
|
||||
ssh_print_hexa("encryption key",session->next_crypto->encryptkey,16);
|
||||
ssh_print_hexa("decryption key",session->next_crypto->decryptkey,16);
|
||||
ssh_print_hexa("Encryption MAC",session->next_crypto->encryptMAC,SHA_DIGEST_LENGTH);
|
||||
@ -346,6 +428,9 @@ static int sig_verify(SSH_SESSION *session, PUBLIC_KEY *pubkey, SIGNATURE *signa
|
||||
int valid=0;
|
||||
char hash[SHA_DIGEST_LENGTH];
|
||||
sha1(digest,SHA_DIGEST_LENGTH,hash);
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("hash to be verified with dsa",hash,SHA_DIGEST_LENGTH);
|
||||
#endif
|
||||
switch(pubkey->type){
|
||||
case TYPE_DSS:
|
||||
valid=DSA_do_verify(hash,SHA_DIGEST_LENGTH,signature->dsa_sign,
|
||||
@ -392,7 +477,7 @@ int signature_verify(SSH_SESSION *session,STRING *signature){
|
||||
if(session->options->wanted_methods[SSH_HOSTKEYS]){
|
||||
if(match(session->options->wanted_methods[SSH_HOSTKEYS],pubkey->type_c)){
|
||||
ssh_set_error(session,SSH_FATAL,"Public key from server (%s) doesn't match user preference (%s)",
|
||||
pubkey->type,session->options->wanted_methods[SSH_HOSTKEYS]);
|
||||
pubkey->type_c,session->options->wanted_methods[SSH_HOSTKEYS]);
|
||||
publickey_free(pubkey);
|
||||
return -1;
|
||||
}
|
||||
|
18
libssh/kex.c
18
libssh/kex.c
@ -37,7 +37,7 @@ MA 02111-1307, USA. */
|
||||
#define AES ""
|
||||
#endif
|
||||
|
||||
#define DES "3des-cbc,"
|
||||
#define DES "3des-cbc"
|
||||
#ifdef HAVE_LIBZ
|
||||
#define ZLIB "none,zlib"
|
||||
#else
|
||||
@ -121,7 +121,7 @@ char **space_tokenize(char *chain){
|
||||
/* and a list of prefered objects (what_d) */
|
||||
/* it will return a strduped pointer on the first prefered object found in the available objects list */
|
||||
|
||||
static char *find_matching(char *in_d, char *what_d){
|
||||
char *ssh_find_matching(char *in_d, char *what_d){
|
||||
char ** tok_in, **tok_what;
|
||||
int i_in, i_what;
|
||||
char *ret;
|
||||
@ -190,7 +190,7 @@ int ssh_get_kex(SSH_SESSION *session,int server_kex ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
void list_kex(KEX *kex){
|
||||
void ssh_list_kex(KEX *kex){
|
||||
int i=0;
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("session cookie",kex->cookie,16);
|
||||
@ -214,13 +214,13 @@ int set_kex(SSH_SESSION *session){
|
||||
if(options->wanted_cookie)
|
||||
memcpy(client->cookie,options->wanted_cookie,16);
|
||||
else
|
||||
ssh_get_random(client->cookie,16);
|
||||
ssh_get_random(client->cookie,16,0);
|
||||
client->methods=malloc(10 * sizeof(char **));
|
||||
memset(client->methods,0,10*sizeof(char **));
|
||||
for (i=0;i<10;i++){
|
||||
if(!(wanted=options->wanted_methods[i]))
|
||||
wanted=default_methods[i];
|
||||
client->methods[i]=find_matching(server->methods[i],wanted);
|
||||
client->methods[i]=ssh_find_matching(server->methods[i],wanted);
|
||||
if(!client->methods[i] && i < SSH_LANG_C_S){
|
||||
ssh_set_error(session,SSH_FATAL,"kex error : did not find one of algos %s in list %s for %s",
|
||||
wanted,server->methods[i],ssh_kex_nums[i]);
|
||||
@ -234,7 +234,7 @@ int set_kex(SSH_SESSION *session){
|
||||
}
|
||||
|
||||
/* this function only sends the predefined set of kex methods */
|
||||
void send_kex(SSH_SESSION *session, int server_kex){
|
||||
void ssh_send_kex(SSH_SESSION *session, int server_kex){
|
||||
STRING *str;
|
||||
int i=0;
|
||||
KEX *kex=(server_kex ? &session->server_kex : &session->client_kex);
|
||||
@ -242,7 +242,7 @@ void send_kex(SSH_SESSION *session, int server_kex){
|
||||
buffer_add_u8(session->out_buffer,SSH2_MSG_KEXINIT);
|
||||
buffer_add_data(session->out_buffer,kex->cookie,16);
|
||||
hashbufout_add_cookie(session);
|
||||
list_kex(kex);
|
||||
ssh_list_kex(kex);
|
||||
for(i=0;i<10;i++){
|
||||
str=string_from_char(kex->methods[i]);
|
||||
buffer_add_ssh_string(session->out_hashbuf,str);
|
||||
@ -260,7 +260,7 @@ int verify_existing_algo(int algo, char *name){
|
||||
char *ptr;
|
||||
if(algo>9 || algo <0)
|
||||
return -1;
|
||||
ptr=find_matching(supported_methods[algo],name);
|
||||
ptr=ssh_find_matching(supported_methods[algo],name);
|
||||
if(ptr){
|
||||
free(ptr);
|
||||
return 1;
|
||||
@ -303,7 +303,7 @@ STRING *encrypt_session_key(SSH_SESSION *session, PUBLIC_KEY *svrkey,
|
||||
STRING *data1,*data2;
|
||||
/* first, generate a session key */
|
||||
|
||||
ssh_get_random(session->next_crypto->encryptkey,32);
|
||||
ssh_get_random(session->next_crypto->encryptkey,32,1);
|
||||
memcpy(buffer,session->next_crypto->encryptkey,32);
|
||||
memcpy(session->next_crypto->decryptkey,
|
||||
session->next_crypto->encryptkey,32);
|
||||
|
@ -74,7 +74,8 @@ PRIVATE_KEY *privatekey_from_file(SSH_SESSION *session,char *filename,int type,
|
||||
dsa=PEM_read_DSAPrivateKey(file,NULL,(void *)get_password_specified,passphrase);
|
||||
fclose(file);
|
||||
if(!dsa){
|
||||
ssh_set_error(session,SSH_FATAL,"parsing private key %s : %s",filename,ERR_error_string(ERR_get_error(),NULL));
|
||||
ssh_set_error(session,SSH_FATAL,"parsing private key %s"
|
||||
": %s",filename,ERR_error_string(ERR_get_error(),NULL));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@ -89,7 +90,8 @@ PRIVATE_KEY *privatekey_from_file(SSH_SESSION *session,char *filename,int type,
|
||||
rsa=PEM_read_RSAPrivateKey(file,NULL,(void *)get_password_specified,passphrase);
|
||||
fclose(file);
|
||||
if(!rsa){
|
||||
ssh_set_error(session,SSH_FATAL,"parsing private key %s : %s",filename,ERR_error_string(ERR_get_error(),NULL));
|
||||
ssh_set_error(session,SSH_FATAL,"parsing private key %s"
|
||||
": %s",filename,ERR_error_string(ERR_get_error(),NULL));
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
@ -104,6 +106,44 @@ PRIVATE_KEY *privatekey_from_file(SSH_SESSION *session,char *filename,int type,
|
||||
return privkey;
|
||||
}
|
||||
|
||||
/* same that privatekey_from_file() but without any passphrase things. */
|
||||
PRIVATE_KEY *_privatekey_from_file(void *session,char *filename,int type){
|
||||
FILE *file=fopen(filename,"r");
|
||||
PRIVATE_KEY *privkey;
|
||||
DSA *dsa=NULL;
|
||||
RSA *rsa=NULL;
|
||||
if(!file){
|
||||
ssh_set_error(session,SSH_REQUEST_DENIED,"Error opening %s : %s",filename,strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
if(type==TYPE_DSS){
|
||||
dsa=PEM_read_DSAPrivateKey(file,NULL,NULL,NULL);
|
||||
fclose(file);
|
||||
if(!dsa){
|
||||
ssh_set_error(session,SSH_FATAL,"parsing private key %s"
|
||||
": %s",filename,ERR_error_string(ERR_get_error(),NULL));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (type==TYPE_RSA){
|
||||
rsa=PEM_read_RSAPrivateKey(file,NULL,NULL,NULL);
|
||||
fclose(file);
|
||||
if(!rsa){
|
||||
ssh_set_error(session,SSH_FATAL,"parsing private key %s"
|
||||
": %s",filename,ERR_error_string(ERR_get_error(),NULL));
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
ssh_set_error(session,SSH_FATAL,"Invalid private key type %d",type);
|
||||
return NULL;
|
||||
}
|
||||
privkey=malloc(sizeof(PRIVATE_KEY));
|
||||
privkey->type=type;
|
||||
privkey->dsa_priv=dsa;
|
||||
privkey->rsa_priv=rsa;
|
||||
return privkey;
|
||||
}
|
||||
|
||||
void private_key_free(PRIVATE_KEY *prv){
|
||||
if(prv->dsa_priv)
|
||||
DSA_free(prv->dsa_priv);
|
||||
|
124
libssh/keys.c
124
libssh/keys.c
@ -2,7 +2,7 @@
|
||||
/* decoding a public key (both rsa and dsa), decoding a signature (rsa and dsa), veryfying them */
|
||||
|
||||
/*
|
||||
Copyright 2003,04 Aris Adamantiadis
|
||||
Copyright 2003-2005 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
@ -156,6 +156,77 @@ PUBLIC_KEY *publickey_from_string(STRING *pubkey_s){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PUBLIC_KEY *publickey_from_privatekey(PRIVATE_KEY *prv){
|
||||
PUBLIC_KEY *key=malloc(sizeof(PUBLIC_KEY));
|
||||
key->type=prv->type;
|
||||
switch(key->type){
|
||||
case TYPE_DSS:
|
||||
key->dsa_pub=DSA_new();
|
||||
key->dsa_pub->p=BN_dup(prv->dsa_priv->p);
|
||||
key->dsa_pub->q=BN_dup(prv->dsa_priv->q);
|
||||
key->dsa_pub->pub_key=BN_dup(prv->dsa_priv->pub_key);
|
||||
key->dsa_pub->g=BN_dup(prv->dsa_priv->g);
|
||||
break;
|
||||
case TYPE_RSA:
|
||||
case TYPE_RSA1:
|
||||
key->rsa_pub=RSA_new();
|
||||
key->rsa_pub->e=BN_dup(prv->rsa_priv->e);
|
||||
key->rsa_pub->n=BN_dup(prv->rsa_priv->n);
|
||||
break;
|
||||
}
|
||||
key->type_c=ssh_type_to_char(prv->type);
|
||||
return key;
|
||||
}
|
||||
|
||||
static void dsa_public_to_string(DSA *key, BUFFER *buffer){
|
||||
STRING *p,*q,*g,*n;
|
||||
p=make_bignum_string(key->p);
|
||||
q=make_bignum_string(key->q);
|
||||
g=make_bignum_string(key->g);
|
||||
n=make_bignum_string(key->pub_key);
|
||||
buffer_add_ssh_string(buffer,p);
|
||||
buffer_add_ssh_string(buffer,q);
|
||||
buffer_add_ssh_string(buffer,g);
|
||||
buffer_add_ssh_string(buffer,n);
|
||||
free(p);
|
||||
free(q);
|
||||
free(g);
|
||||
free(n);
|
||||
}
|
||||
|
||||
static void rsa_public_to_string(RSA *key, BUFFER *buffer){
|
||||
STRING *e, *n;
|
||||
e=make_bignum_string(key->e);
|
||||
n=make_bignum_string(key->n);
|
||||
buffer_add_ssh_string(buffer,e);
|
||||
buffer_add_ssh_string(buffer,n);
|
||||
free(e);
|
||||
free(n);
|
||||
}
|
||||
|
||||
STRING *publickey_to_string(PUBLIC_KEY *key){
|
||||
STRING *type;
|
||||
STRING *ret;
|
||||
BUFFER *buf;
|
||||
type=string_from_char(ssh_type_to_char(key->type));
|
||||
buf=buffer_new();
|
||||
buffer_add_ssh_string(buf,type);
|
||||
switch(key->type){
|
||||
case TYPE_DSS:
|
||||
dsa_public_to_string(key->dsa_pub,buf);
|
||||
break;
|
||||
case TYPE_RSA:
|
||||
case TYPE_RSA1:
|
||||
rsa_public_to_string(key->rsa_pub,buf);
|
||||
break;
|
||||
}
|
||||
ret=string_new(buffer_get_len(buf));
|
||||
string_fill(ret,buffer_get(buf),buffer_get_len(buf));
|
||||
buffer_free(buf);
|
||||
free(type);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Signature decoding functions */
|
||||
|
||||
STRING *signature_to_string(SIGNATURE *sign){
|
||||
@ -325,22 +396,31 @@ static STRING *RSA_do_sign(void *payload,int len,RSA *privkey){
|
||||
return sign;
|
||||
}
|
||||
|
||||
/* this function signs the session id (known as H) as a string then the content of sigbuf */
|
||||
STRING *ssh_do_sign(SSH_SESSION *session,BUFFER *sigbuf, PRIVATE_KEY *privatekey){
|
||||
SHACTX *ctx;
|
||||
STRING *session_str=string_new(SHA_DIGEST_LEN);
|
||||
char hash[SHA_DIGEST_LEN];
|
||||
SIGNATURE *sign;
|
||||
STRING *signature;
|
||||
string_fill(session_str,session->current_crypto->session_id,SHA_DIGEST_LENGTH);
|
||||
CRYPTO *crypto=session->current_crypto?session->current_crypto:session->next_crypto;
|
||||
string_fill(session_str,crypto->session_id,SHA_DIGEST_LENGTH);
|
||||
ctx=sha1_init();
|
||||
sha1_update(ctx,session_str,string_len(session_str)+4);
|
||||
sha1_update(ctx,buffer_get(sigbuf),buffer_get_len(sigbuf));
|
||||
sha1_final(hash,ctx);
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("Hash being signed with dsa",hash,SHA_DIGEST_LENGTH);
|
||||
#endif
|
||||
free(session_str);
|
||||
sign=malloc(sizeof(SIGNATURE));
|
||||
switch(privatekey->type){
|
||||
case TYPE_DSS:
|
||||
sign->dsa_sign=DSA_do_sign(hash,SHA_DIGEST_LENGTH,privatekey->dsa_priv);
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_bignum("r",sign->dsa_sign->r);
|
||||
ssh_print_bignum("s",sign->dsa_sign->s);
|
||||
#endif
|
||||
sign->rsa_sign=NULL;
|
||||
break;
|
||||
case TYPE_RSA:
|
||||
@ -368,3 +448,43 @@ STRING *ssh_encrypt_rsa1(SSH_SESSION *session, STRING *data, PUBLIC_KEY *key){
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* this function signs the session id */
|
||||
STRING *ssh_sign_session_id(SSH_SESSION *session, PRIVATE_KEY *privatekey){
|
||||
SHACTX *ctx;
|
||||
char hash[SHA_DIGEST_LEN];
|
||||
SIGNATURE *sign;
|
||||
STRING *signature;
|
||||
CRYPTO *crypto=session->current_crypto?session->current_crypto:session->next_crypto;
|
||||
ctx=sha1_init();
|
||||
sha1_update(ctx,crypto->session_id,SHA_DIGEST_LENGTH);
|
||||
sha1_final(hash,ctx);
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("Hash being signed with dsa",hash,SHA_DIGEST_LENGTH);
|
||||
#endif
|
||||
sign=malloc(sizeof(SIGNATURE));
|
||||
switch(privatekey->type){
|
||||
case TYPE_DSS:
|
||||
sign->dsa_sign=DSA_do_sign(hash,SHA_DIGEST_LENGTH,privatekey->dsa_priv);
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_bignum("r",sign->dsa_sign->r);
|
||||
ssh_print_bignum("s",sign->dsa_sign->s);
|
||||
#endif
|
||||
sign->rsa_sign=NULL;
|
||||
break;
|
||||
case TYPE_RSA:
|
||||
sign->rsa_sign=RSA_do_sign(hash,SHA_DIGEST_LENGTH,privatekey->rsa_priv);
|
||||
sign->dsa_sign=NULL;
|
||||
break;
|
||||
}
|
||||
sign->type=privatekey->type;
|
||||
if(!sign->dsa_sign && !sign->rsa_sign){
|
||||
ssh_set_error(session,SSH_FATAL,"Signing : openssl error");
|
||||
signature_free(sign);
|
||||
return NULL;
|
||||
}
|
||||
signature=signature_to_string(sign);
|
||||
signature_free(sign);
|
||||
return signature;
|
||||
}
|
||||
|
||||
|
@ -43,33 +43,37 @@ void ssh_options_set_port(SSH_OPTIONS *opt, unsigned int port){
|
||||
opt->port=port&0xffff;
|
||||
}
|
||||
SSH_OPTIONS *ssh_options_copy(SSH_OPTIONS *opt){
|
||||
SSH_OPTIONS *ret=ssh_options_new();
|
||||
SSH_OPTIONS *ret=ssh_options_new();
|
||||
int i;
|
||||
ret->fd=opt->fd;
|
||||
ret->fd=opt->fd;
|
||||
ret->port=opt->port;
|
||||
if(opt->username)
|
||||
ret->username=strdup(opt->username);
|
||||
ret->username=strdup(opt->username);
|
||||
if(opt->host)
|
||||
ret->host=strdup(opt->host);
|
||||
ret->host=strdup(opt->host);
|
||||
if(opt->bindaddr)
|
||||
ret->host=strdup(opt->bindaddr);
|
||||
ret->host=strdup(opt->bindaddr);
|
||||
if(opt->identity)
|
||||
ret->identity=strdup(opt->identity);
|
||||
ret->identity=strdup(opt->identity);
|
||||
if(opt->ssh_dir)
|
||||
ret->ssh_dir=strdup(opt->ssh_dir);
|
||||
if(opt->known_hosts_file)
|
||||
ret->known_hosts_file=strdup(opt->known_hosts_file);
|
||||
for(i=0;i<10;++i)
|
||||
if(opt->wanted_methods[i])
|
||||
ret->wanted_methods[i]=strdup(opt->wanted_methods[i]);
|
||||
ret->passphrase_function=opt->passphrase_function;
|
||||
ret->connect_status_function=opt->connect_status_function;
|
||||
ret->connect_status_arg=opt->connect_status_arg;
|
||||
ret->timeout=opt->timeout;
|
||||
ret->timeout_usec=opt->timeout_usec;
|
||||
if(opt->known_hosts_file)
|
||||
ret->known_hosts_file=strdup(opt->known_hosts_file);
|
||||
if(opt->dsakey)
|
||||
ret->dsakey=strdup(opt->dsakey);
|
||||
if(opt->rsakey)
|
||||
ret->rsakey=strdup(opt->rsakey);
|
||||
for(i=0;i<10;++i)
|
||||
if(opt->wanted_methods[i])
|
||||
ret->wanted_methods[i]=strdup(opt->wanted_methods[i]);
|
||||
ret->passphrase_function=opt->passphrase_function;
|
||||
ret->connect_status_function=opt->connect_status_function;
|
||||
ret->connect_status_arg=opt->connect_status_arg;
|
||||
ret->timeout=opt->timeout;
|
||||
ret->timeout_usec=opt->timeout_usec;
|
||||
ret->ssh2allowed=opt->ssh2allowed;
|
||||
ret->ssh1allowed=opt->ssh1allowed;
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ssh_options_free(SSH_OPTIONS *opt){
|
||||
@ -85,6 +89,10 @@ void ssh_options_free(SSH_OPTIONS *opt){
|
||||
free(opt->bindaddr);
|
||||
if(opt->ssh_dir)
|
||||
free(opt->ssh_dir);
|
||||
if(opt->dsakey)
|
||||
free(opt->dsakey);
|
||||
if(opt->rsakey)
|
||||
free(opt->rsakey);
|
||||
for(i=0;i<10;i++)
|
||||
if(opt->wanted_methods[i])
|
||||
free(opt->wanted_methods[i]);
|
||||
@ -142,6 +150,13 @@ void ssh_options_set_identity(SSH_OPTIONS *opt, char *identity){
|
||||
opt->identity=strdup(buffer);
|
||||
}
|
||||
|
||||
void ssh_options_set_dsa_server_key(SSH_OPTIONS *opt, char *dsakey){
|
||||
opt->dsakey=strdup(dsakey);
|
||||
}
|
||||
void ssh_options_set_rsa_server_key(SSH_OPTIONS *opt, char *rsakey){
|
||||
opt->rsakey=strdup(rsakey);
|
||||
}
|
||||
|
||||
void ssh_options_set_banner(SSH_OPTIONS *opt, char *banner){
|
||||
if(opt->banner)
|
||||
free(opt->banner);
|
||||
|
@ -138,7 +138,7 @@ static int packet_read2(SSH_SESSION *session){
|
||||
ssh_set_error(session,SSH_FATAL,"Packet too short to read padding");
|
||||
return -1;
|
||||
}
|
||||
ssh_say(3,"%hhd bytes padding\n",padding);
|
||||
ssh_say(3,"%hhd bytes padding, %d bytes left in buffer\n",padding,buffer_get_rest_len(session->in_buffer));
|
||||
if(padding > buffer_get_rest_len(session->in_buffer)){
|
||||
ssh_set_error(session,SSH_FATAL,"invalid padding: %d (%d resting)",padding,buffer_get_rest_len(session->in_buffer));
|
||||
#ifdef DEBUG_CRYPTO
|
||||
@ -147,8 +147,10 @@ static int packet_read2(SSH_SESSION *session){
|
||||
return -1;
|
||||
}
|
||||
buffer_pass_bytes_end(session->in_buffer,padding);
|
||||
ssh_say(3,"After padding, %d bytes left in buffer\n",buffer_get_rest_len(session->in_buffer));
|
||||
#ifdef HAVE_LIBZ
|
||||
if(session->current_crypto && session->current_crypto->do_compress_in){
|
||||
ssh_say(3,"Decompressing ...\n");
|
||||
decompress_buffer(session,session->in_buffer);
|
||||
}
|
||||
#endif
|
||||
@ -320,6 +322,7 @@ static int packet_send2(SSH_SESSION *session){
|
||||
ssh_say(3,"Writing on the wire a packet having %ld bytes before",currentlen);
|
||||
#ifdef HAVE_LIBZ
|
||||
if(session->current_crypto && session->current_crypto->do_compress_out){
|
||||
ssh_say(3,"Compressing ...\n");
|
||||
compress_buffer(session,session->out_buffer);
|
||||
currentlen=buffer_get_len(session->out_buffer);
|
||||
}
|
||||
@ -328,7 +331,7 @@ static int packet_send2(SSH_SESSION *session){
|
||||
if(padding<4)
|
||||
padding+=blocksize;
|
||||
if(session->current_crypto)
|
||||
ssh_get_random(padstring,padding);
|
||||
ssh_get_random(padstring,padding,0);
|
||||
else
|
||||
memset(padstring,0,padding);
|
||||
finallen=htonl(currentlen+padding+1);
|
||||
|
141
libssh/server.c
141
libssh/server.c
@ -1,9 +1,6 @@
|
||||
/* server.c */
|
||||
|
||||
/* No. It doesn't work yet. It's just hard to have 2 separated trees, one for releases
|
||||
* and one for development */
|
||||
/*
|
||||
Copyright 2004 Aris Adamantiadis
|
||||
Copyright 2004,2005 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
@ -35,6 +32,7 @@ MA 02111-1307, USA. */
|
||||
#include <string.h>
|
||||
#include "libssh/libssh.h"
|
||||
#include "libssh/server.h"
|
||||
#include "libssh/ssh2.h"
|
||||
static int bind_socket(SSH_BIND *ssh_bind,char *hostname, int port) {
|
||||
struct sockaddr_in myaddr;
|
||||
int opt = 1;
|
||||
@ -113,55 +111,79 @@ void ssh_bind_fd_toaccept(SSH_BIND *ssh_bind){
|
||||
|
||||
SSH_SESSION *ssh_bind_accept(SSH_BIND *ssh_bind){
|
||||
SSH_SESSION *session;
|
||||
PRIVATE_KEY *dsa=NULL, *rsa=NULL;
|
||||
if(ssh_bind->bindfd<0){
|
||||
ssh_set_error(ssh_bind,SSH_FATAL,"Can't accept new clients on a "
|
||||
"not bound socket.");
|
||||
return NULL;
|
||||
}
|
||||
if(!ssh_bind->options->dsakey && !ssh_bind->options->rsakey){
|
||||
ssh_set_error(ssh_bind,SSH_FATAL,"DSA or RSA host key file must be set before accept()");
|
||||
return NULL;
|
||||
}
|
||||
if(ssh_bind->options->dsakey){
|
||||
dsa=_privatekey_from_file(ssh_bind,ssh_bind->options->dsakey,TYPE_DSS);
|
||||
if(!dsa)
|
||||
return NULL;
|
||||
ssh_say(2,"Dsa private key read successfuly\n");
|
||||
}
|
||||
if(ssh_bind->options->rsakey){
|
||||
rsa=_privatekey_from_file(ssh_bind,ssh_bind->options->rsakey,TYPE_RSA);
|
||||
if(!rsa){
|
||||
if(dsa)
|
||||
private_key_free(dsa);
|
||||
return NULL;
|
||||
}
|
||||
ssh_say(2,"RSA private key read successfuly\n");
|
||||
}
|
||||
int fd=accept(ssh_bind->bindfd,NULL,NULL);
|
||||
if(fd<0){
|
||||
ssh_set_error(ssh_bind,SSH_FATAL,"Accepting a new connection: %s",
|
||||
strerror(errno));
|
||||
if(dsa)
|
||||
private_key_free(dsa);
|
||||
if(rsa)
|
||||
private_key_free(rsa);
|
||||
return NULL;
|
||||
}
|
||||
session=ssh_new(ssh_options_copy(ssh_bind->options));
|
||||
session=ssh_new();
|
||||
session->server=1;
|
||||
session->version=2;
|
||||
session->fd=fd;
|
||||
session->options=ssh_options_copy(ssh_bind->options);
|
||||
session->dsa_key=dsa;
|
||||
session->rsa_key=rsa;
|
||||
return session;
|
||||
}
|
||||
|
||||
/* do the banner and key exchange */
|
||||
int ssh_accept(SSH_SESSION *session){
|
||||
ssh_send_banner(session,1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
extern char *supported_methods[];
|
||||
|
||||
int server_set_kex(SSH_SESSION * session) {
|
||||
KEX *server = &session->server_kex;
|
||||
SSH_OPTIONS *options = session->options;
|
||||
int i;
|
||||
char *wanted;
|
||||
if (!options) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Options structure is null(client's bug)");
|
||||
return -1;
|
||||
}
|
||||
memset(server,0,sizeof(KEX));
|
||||
// the program might ask for a specific cookie to be sent. useful for server
|
||||
// debugging
|
||||
if (options->wanted_cookie)
|
||||
memcpy(server->cookie, options->wanted_cookie, 16);
|
||||
else
|
||||
ssh_get_random(server->cookie, 16);
|
||||
ssh_get_random(server->cookie, 16,0);
|
||||
if(session->dsa_key && session->rsa_key){
|
||||
ssh_options_set_wanted_algos(options,SSH_HOSTKEYS,"ssh-dss,ssh-rsa");
|
||||
} else {
|
||||
if(session->dsa_key)
|
||||
ssh_options_set_wanted_algos(options,SSH_HOSTKEYS,"ssh-dss");
|
||||
else
|
||||
ssh_options_set_wanted_algos(options,SSH_HOSTKEYS,"ssh-rsa");
|
||||
}
|
||||
server->methods = malloc(10 * sizeof(char **));
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (!(wanted = options->wanted_methods[i]))
|
||||
wanted = supported_methods[i];
|
||||
server->methods[i] = wanted;
|
||||
printf("server->methods[%d]=%s\n",i,wanted);
|
||||
if (!(wanted = options->wanted_methods[i]))
|
||||
wanted = supported_methods[i];
|
||||
server->methods[i] = wanted;
|
||||
printf("server->methods[%d]=%s\n",i,wanted);
|
||||
}
|
||||
if (!server->methods[i]) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"kex error : did not find algo");
|
||||
@ -170,5 +192,76 @@ int server_set_kex(SSH_SESSION * session) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*/
|
||||
static int dh_handshake_server(SSH_SESSION *session){
|
||||
STRING *e,*f,*pubkey,*sign;
|
||||
PUBLIC_KEY *pub;
|
||||
PRIVATE_KEY *prv;
|
||||
BUFFER *buf=buffer_new();
|
||||
if(packet_wait(session, SSH2_MSG_KEXDH_INIT ,1))
|
||||
return -1;
|
||||
e=buffer_get_ssh_string(session->in_buffer);
|
||||
if(!e){
|
||||
ssh_set_error(session,SSH_FATAL,"No e number in client request");
|
||||
return -1;
|
||||
}
|
||||
dh_import_e(session,e);
|
||||
dh_generate_y(session);
|
||||
dh_generate_f(session);
|
||||
f=dh_get_f(session);
|
||||
switch(session->hostkeys){
|
||||
case TYPE_DSS:
|
||||
prv=session->dsa_key;
|
||||
break;
|
||||
case TYPE_RSA:
|
||||
prv=session->rsa_key;
|
||||
break;
|
||||
}
|
||||
pub=publickey_from_privatekey(prv);
|
||||
pubkey=publickey_to_string(pub);
|
||||
publickey_free(pub);
|
||||
dh_import_pubkey(session,pubkey);
|
||||
dh_build_k(session);
|
||||
make_sessionid(session);
|
||||
sign=ssh_sign_session_id(session,prv);
|
||||
buffer_free(buf);
|
||||
private_key_free(prv);
|
||||
buffer_add_u8(session->out_buffer,SSH2_MSG_KEXDH_REPLY);
|
||||
buffer_add_ssh_string(session->out_buffer,pubkey);
|
||||
buffer_add_ssh_string(session->out_buffer,f);
|
||||
buffer_add_ssh_string(session->out_buffer,sign);
|
||||
free(sign);
|
||||
packet_send(session);
|
||||
free(f);
|
||||
packet_clear_out(session);
|
||||
buffer_add_u8(session->out_buffer,SSH2_MSG_NEWKEYS);
|
||||
packet_send(session);
|
||||
ssh_say(2,"SSH_MSG_NEWKEYS sent\n");
|
||||
|
||||
packet_wait(session,SSH2_MSG_NEWKEYS,1);
|
||||
ssh_say(2,"Got SSH_MSG_NEWKEYS\n");
|
||||
generate_session_keys(session);
|
||||
/* once we got SSH2_MSG_NEWKEYS we can switch next_crypto and current_crypto */
|
||||
if(session->current_crypto)
|
||||
crypto_free(session->current_crypto);
|
||||
/* XXX later, include a function to change keys */
|
||||
session->current_crypto=session->next_crypto;
|
||||
session->next_crypto=crypto_new();
|
||||
return 0;
|
||||
}
|
||||
/* do the banner and key exchange */
|
||||
int ssh_accept(SSH_SESSION *session){
|
||||
ssh_send_banner(session,1);
|
||||
ssh_crypto_init();
|
||||
session->clientbanner=ssh_get_banner(session);
|
||||
server_set_kex(session);
|
||||
ssh_send_kex(session,1);
|
||||
if(ssh_get_kex(session,1))
|
||||
return -1;
|
||||
ssh_list_kex(&session->client_kex);
|
||||
crypt_set_algorithms_server(session);
|
||||
if(dh_handshake_server(session))
|
||||
return -1;
|
||||
session->connected=1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -67,6 +67,10 @@ void ssh_cleanup(SSH_SESSION *session){
|
||||
free(session->server_kex.methods[i]);
|
||||
free(session->client_kex.methods);
|
||||
free(session->server_kex.methods);
|
||||
if(session->dsa_key)
|
||||
private_key_free(session->dsa_key);
|
||||
if(session->rsa_key)
|
||||
private_key_free(session->rsa_key);
|
||||
memset(session,'X',sizeof(SSH_SESSION)); /* burn connection, it could hangs
|
||||
sensitive datas */
|
||||
free(session);
|
||||
|
@ -299,7 +299,6 @@ static int crypt_set_algorithms2(SSH_SESSION *session){
|
||||
}
|
||||
ssh_say(2,"Set input algorithm %s\n",wanted);
|
||||
session->next_crypto->in_cipher=cipher_new(i);
|
||||
|
||||
/* compression */
|
||||
if(strstr(session->client_kex.methods[SSH_COMP_C_S],"zlib"))
|
||||
session->next_crypto->do_compress_out=1;
|
||||
@ -327,3 +326,61 @@ int crypt_set_algorithms(SSH_SESSION *session){
|
||||
crypt_set_algorithms2(session);
|
||||
}
|
||||
|
||||
int crypt_set_algorithms_server(SSH_SESSION *session){
|
||||
/* we must scan the kex entries to find crypto algorithms and set their appropriate structure */
|
||||
int i=0;
|
||||
/* out */
|
||||
char *server=session->server_kex.methods[SSH_CRYPT_S_C];
|
||||
char *client=session->client_kex.methods[SSH_CRYPT_S_C];
|
||||
char *match=ssh_find_matching(client,server);
|
||||
while(ssh_ciphertab[i].name && strcmp(match,ssh_ciphertab[i].name))
|
||||
i++;
|
||||
if(!ssh_ciphertab[i].name){
|
||||
ssh_set_error(session,SSH_FATAL,"Crypt_set_algorithms : no crypto algorithm function found for %s",server);
|
||||
return -1;
|
||||
}
|
||||
ssh_say(2,"Set output algorithm %s\n",match);
|
||||
session->next_crypto->out_cipher=cipher_new(i);
|
||||
i=0;
|
||||
/* in */
|
||||
client=session->client_kex.methods[SSH_CRYPT_C_S];
|
||||
server=session->server_kex.methods[SSH_CRYPT_S_C];
|
||||
match=ssh_find_matching(client,server);
|
||||
while(ssh_ciphertab[i].name && strcmp(match,ssh_ciphertab[i].name))
|
||||
i++;
|
||||
if(!ssh_ciphertab[i].name){
|
||||
ssh_set_error(session,SSH_FATAL,"Crypt_set_algorithms : no crypto algorithm function found for %s",server);
|
||||
return -1;
|
||||
}
|
||||
ssh_say(2,"Set input algorithm %s\n",match);
|
||||
session->next_crypto->in_cipher=cipher_new(i);
|
||||
/* compression */
|
||||
client=session->client_kex.methods[SSH_CRYPT_C_S];
|
||||
server=session->server_kex.methods[SSH_CRYPT_C_S];
|
||||
match=ssh_find_matching(client,server);
|
||||
if(match && !strcmp(match,"zlib")){
|
||||
ssh_say(2,"enabling C->S compression\n");
|
||||
session->next_crypto->do_compress_in=1;
|
||||
}
|
||||
|
||||
client=session->client_kex.methods[SSH_CRYPT_S_C];
|
||||
server=session->server_kex.methods[SSH_CRYPT_S_C];
|
||||
match=ssh_find_matching(client,server);
|
||||
if(match && !strcmp(match,"zlib")){
|
||||
ssh_say(2,"enabling S->C compression\n");
|
||||
session->next_crypto->do_compress_out=1;
|
||||
}
|
||||
|
||||
server=session->server_kex.methods[SSH_HOSTKEYS];
|
||||
client=session->client_kex.methods[SSH_HOSTKEYS];
|
||||
match=ssh_find_matching(client,server);
|
||||
if(!strcmp(match,"ssh-dss"))
|
||||
session->hostkeys=TYPE_DSS;
|
||||
else if(!strcmp(match,"ssh-rsa"))
|
||||
session->hostkeys=TYPE_RSA;
|
||||
else {
|
||||
ssh_set_error(session,SSH_FATAL,"cannot know what %s is into %s",match,server);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
30
samplesshd.c
30
samplesshd.c
@ -27,7 +27,10 @@ int main(int argc, char **argv){
|
||||
SSH_OPTIONS *options=ssh_options_new();
|
||||
SSH_SESSION *session;
|
||||
SSH_BIND *ssh_bind;
|
||||
SSH_MESSAGE *message;
|
||||
ssh_options_getopt(options,&argc,argv);
|
||||
ssh_options_set_dsa_server_key(options,"/etc/ssh/ssh_host_dsa_key");
|
||||
ssh_options_set_rsa_server_key(options,"/etc/ssh/ssh_host_rsa_key");
|
||||
ssh_bind=ssh_bind_new();
|
||||
ssh_bind_set_options(ssh_bind,options);
|
||||
if(ssh_bind_listen(ssh_bind)<0){
|
||||
@ -40,25 +43,14 @@ int main(int argc, char **argv){
|
||||
return 1;
|
||||
}
|
||||
printf("Socket connecté : %d\n",ssh_get_fd(session));
|
||||
ssh_accept(session);
|
||||
if(ssh_accept(session)){
|
||||
printf("ssh_accept : %s\n",ssh_get_error(session));
|
||||
return 1;
|
||||
}
|
||||
do {
|
||||
message=ssh_message_get(session);
|
||||
} while (message);
|
||||
printf("error : %s\n",ssh_get_error(session));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
server->clientbanner=ssh_get_banner(server);
|
||||
if(!server->clientbanner){
|
||||
printf("%s\n",ssh_get_error(NULL));
|
||||
return -1;
|
||||
}
|
||||
server_set_kex(server);
|
||||
send_kex(server,1);
|
||||
if (ssh_get_kex(server,1)){
|
||||
printf("%s \n",ssh_get_error(NULL));
|
||||
return -1;
|
||||
}
|
||||
list_kex(&server->client_kex);
|
||||
|
||||
while(1);
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
Загрузка…
Ссылка в новой задаче
Block a user