From 5c26ae735483d140f802d58b1872b2fe9468d219 Mon Sep 17 00:00:00 2001 From: Aris Adamantiadis Date: Sun, 7 Aug 2005 10:48:08 +0000 Subject: server kex done :) git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@6 7dcaeef0-15fb-0310-b436-a5af3365683c --- Doxyfile | 4 +- include/libssh/libssh.h | 13 ++-- include/libssh/priv.h | 25 +++++- include/libssh/server.h | 18 +++++ include/libssh/ssh2.h | 2 +- libssh/Makefile.in | 2 +- libssh/auth.c | 2 +- libssh/base64.c | 2 +- libssh/client.c | 12 +-- libssh/dh.c | 203 ++++++++++++++++++++++++++++++++++-------------- libssh/kex.c | 18 ++--- libssh/keyfiles.c | 44 ++++++++++- libssh/keys.c | 124 ++++++++++++++++++++++++++++- libssh/options.c | 49 ++++++++---- libssh/packet.c | 7 +- libssh/server.c | 141 +++++++++++++++++++++++++++------ libssh/session.c | 4 + libssh/wrapper.c | 59 +++++++++++++- samplesshd.c | 30 +++---- 19 files changed, 601 insertions(+), 158 deletions(-) diff --git a/Doxyfile b/Doxyfile index 0cf1030f..8fa78bb0 100644 --- a/Doxyfile +++ b/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 \ diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h index 0fc40178..1986c8a8 100644 --- a/include/libssh/libssh.h +++ b/include/libssh/libssh.h @@ -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, diff --git a/include/libssh/priv.h b/include/libssh/priv.h index 7edb8d00..1def7d45 100644 --- a/include/libssh/priv.h +++ b/include/libssh/priv.h @@ -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(); diff --git a/include/libssh/server.h b/include/libssh/server.h index 8e68f137..ef86febe 100644 --- a/include/libssh/server.h +++ b/include/libssh/server.h @@ -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 diff --git a/include/libssh/ssh2.h b/include/libssh/ssh2.h index e6dc04f5..bd89f4e1 100644 --- a/include/libssh/ssh2.h +++ b/include/libssh/ssh2.h @@ -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 diff --git a/libssh/Makefile.in b/libssh/Makefile.in index ee6b5dd1..6eed8135 100644 --- a/libssh/Makefile.in +++ b/libssh/Makefile.in @@ -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@ diff --git a/libssh/auth.c b/libssh/auth.c index 9819ecd0..938dff6b 100644 --- a/libssh/auth.c +++ b/libssh/auth.c @@ -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 diff --git a/libssh/base64.c b/libssh/base64.c index 849c2ca5..1f0b415d 100644 --- a/libssh/base64.c +++ b/libssh/base64.c @@ -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 diff --git a/libssh/client.c b/libssh/client.c index ef61115f..9411d5ec 100644 --- a/libssh/client.c +++ b/libssh/client.c @@ -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); diff --git a/libssh/dh.c b/libssh/dh.c index 25bf5ae6..407fe97e 100644 --- a/libssh/dh.c +++ b/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;i16) + printf ("\n "); + for(i=0;inext_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); - - 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(session->out_hashbuf)); - 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); + 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); + + 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(server_hash)); + buffer_add_u32(buf,len); + //sha1_update(ctx,&len,4); + + 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); +#ifdef DEBUG_CRYPTO + 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); + 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; } diff --git a/libssh/kex.c b/libssh/kex.c index 4a8c30be..a7d3a175 100644 --- a/libssh/kex.c +++ b/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); diff --git a/libssh/keyfiles.c b/libssh/keyfiles.c index 4891ab5a..93223538 100644 --- a/libssh/keyfiles.c +++ b/libssh/keyfiles.c @@ -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); diff --git a/libssh/keys.c b/libssh/keys.c index 16a58db0..a5def00e 100644 --- a/libssh/keys.c +++ b/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; +} + diff --git a/libssh/options.c b/libssh/options.c index bde7f5e4..e1c166d5 100644 --- a/libssh/options.c +++ b/libssh/options.c @@ -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); diff --git a/libssh/packet.c b/libssh/packet.c index 89132f9c..0f86f61a 100644 --- a/libssh/packet.c +++ b/libssh/packet.c @@ -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); diff --git a/libssh/server.c b/libssh/server.c index 25f760ad..62294436 100644 --- a/libssh/server.c +++ b/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 #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; +} diff --git a/libssh/session.c b/libssh/session.c index bfc6e58e..1ea071e0 100644 --- a/libssh/session.c +++ b/libssh/session.c @@ -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); diff --git a/libssh/wrapper.c b/libssh/wrapper.c index 1c49ed79..9d418df0 100644 --- a/libssh/wrapper.c +++ b/libssh/wrapper.c @@ -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; +} diff --git a/samplesshd.c b/samplesshd.c index 249f35df..d81049c5 100644 --- a/samplesshd.c +++ b/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); - 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; + if(ssh_accept(session)){ + printf("ssh_accept : %s\n",ssh_get_error(session)); + return 1; } - list_kex(&server->client_kex); - - while(1); + do { + message=ssh_message_get(session); + } while (message); + printf("error : %s\n",ssh_get_error(session)); return 0; } -*/ + -- cgit v1.2.3