From: Nikos Mavrogiannopoulos Date: Sat, 8 Apr 2000 16:14:35 +0000 (+0000) Subject: Handshake implementation was improved. Still no key exchange algorithm. X-Git-Tag: gnutls0-0-4~95 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c3abd55838e6a62328641cfdcc76dc88ddac9059;p=thirdparty%2Fgnutls.git Handshake implementation was improved. Still no key exchange algorithm. --- diff --git a/src/cli.c b/src/cli.c index a8eecc004e..d018ee3474 100644 --- a/src/cli.c +++ b/src/cli.c @@ -6,7 +6,7 @@ #include #include #include -#include "port.h" +#include #define SA struct sockaddr #define ERR(err,s) if (err==-1) {perror(s);return(1);} @@ -37,6 +37,7 @@ int main() if (ret<0) { fprintf(stderr, "handshake failed(%d)\n", ret); + return 1; } else { fprintf(stderr, "handshake finished\n"); } @@ -46,8 +47,10 @@ int main() if (gnutls_is_fatal_error(ret)==1) { if (ret == GNUTLS_E_CLOSURE_ALERT_RECEIVED) { fprintf(stderr, "Peer has closed the GNUTLS connection\n"); + return 0; } else { fprintf(stderr, "Received corrupted data(%d)\n", ret); + return 1; } } else { fprintf(stdout, "Received: %s\n", buffer); @@ -57,8 +60,10 @@ int main() if (gnutls_is_fatal_error(ret)==1) { if (ret == GNUTLS_E_CLOSURE_ALERT_RECEIVED) { fprintf(stderr, "Peer has closed the GNUTLS connection\n"); + return 0; } else { fprintf(stderr, "Received corrupted data(%d)\n", ret); + return 1; } } else { fprintf(stdout, "Received: %s\n", buffer); diff --git a/src/debug.c b/src/debug.c index a696e1f8ea..9343de237d 100644 --- a/src/debug.c +++ b/src/debug.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "gnutls_int.h" #include "gnutls_errors.h" diff --git a/src/gnutls.c b/src/gnutls.c index 997c4ded63..33289f0ff8 100644 --- a/src/gnutls.c +++ b/src/gnutls.c @@ -1,4 +1,5 @@ #include +#include #include "gnutls_int.h" #include "gnutls_errors.h" #include "debug.h" @@ -7,7 +8,6 @@ #include "gnutls_cipher.h" #include "gnutls_buffers.h" #include "gnutls_handshake.h" -#include int gnutls_init(GNUTLS_STATE * state, ConnectionEnd con_end) { @@ -501,7 +501,7 @@ ssize_t gnutls_recv_int(int cd, GNUTLS_STATE state, ContentType type, if (ret != gcipher.length) { #ifdef DEBUG fprintf(stderr, - "Received packet with length: %d\nExpecting %d\n", + "Received packet with length: %d\nExpected %d\n", ret, gcipher.length); #endif gnutls_free(gcipher.fragment); @@ -584,12 +584,13 @@ ssize_t gnutls_recv_int(int cd, GNUTLS_STATE state, ContentType type, break; case GNUTLS_CHANGE_CIPHER_SPEC: - if (type != GNUTLS_CHANGE_CIPHER_SPEC) + + if (type != GNUTLS_CHANGE_CIPHER_SPEC) { return GNUTLS_E_UNEXPECTED_PACKET; + } if (((ChangeCipherSpecType) - tmpdata[0]) == - GNUTLS_TYPE_CHANGE_CIPHER_SPEC && tmplen == 1) { - ret = _gnutls_connection_state_init(state); + tmpdata[0]) == GNUTLS_TYPE_CHANGE_CIPHER_SPEC && tmplen == 1) { + ret = 0; // _gnutls_connection_state_init(state); } else { state->gnutls_internals.valid_connection @@ -602,14 +603,17 @@ ssize_t gnutls_recv_int(int cd, GNUTLS_STATE state, ContentType type, return ret; case GNUTLS_HANDSHAKE: + if (type == GNUTLS_HANDSHAKE) { ret = _gnutls_recv_handshake - (cd, state, tmpdata, tmplen); + (cd, state, tmpdata, tmplen, data, sizeofdata); + gnutls_free(tmpdata); state-> connection_state.read_sequence_number++; } else { + ret = GNUTLS_E_RECEIVED_BAD_MESSAGE; } return ret; diff --git a/src/gnutls_algorithms.c b/src/gnutls_algorithms.c index a6fa951a75..f4aeacafce 100644 --- a/src/gnutls_algorithms.c +++ b/src/gnutls_algorithms.c @@ -1,4 +1,5 @@ #include +#include #include "gnutls_int.h" #include "gnutls_algorithms.h" diff --git a/src/gnutls_buffers.c b/src/gnutls_buffers.c index 334a54e986..9b8b3fd6f1 100644 --- a/src/gnutls_buffers.c +++ b/src/gnutls_buffers.c @@ -1,4 +1,5 @@ #include +#include #include "gnutls_int.h" #include "gnutls_errors.h" diff --git a/src/gnutls_cipher.c b/src/gnutls_cipher.c index be2caa30bd..2d8ee74514 100644 --- a/src/gnutls_cipher.c +++ b/src/gnutls_cipher.c @@ -1,10 +1,10 @@ #include +#include #include "gnutls_int.h" #include "gnutls_errors.h" #include "gnutls_compress.h" #include "gnutls_cipher.h" #include "gnutls_algorithms.h" -#include #define MD5_DIGEST 16 #define SHA_DIGEST 20 diff --git a/src/gnutls_compress.c b/src/gnutls_compress.c index 9938da3b5e..fa0d2bb11b 100644 --- a/src/gnutls_compress.c +++ b/src/gnutls_compress.c @@ -1,4 +1,5 @@ #include +#include #include "gnutls_int.h" #include "gnutls_compress.h" #include "gnutls_errors.h" diff --git a/src/gnutls_errors.c b/src/gnutls_errors.c index a8c6e10251..b571eb7adf 100644 --- a/src/gnutls_errors.c +++ b/src/gnutls_errors.c @@ -18,7 +18,9 @@ int gnutls_is_fatal_error( int error) { case GNUTLS_E_RECEIVED_BAD_MESSAGE: case GNUTLS_E_RECEIVED_MORE_DATA: case GNUTLS_E_UNEXPECTED_PACKET: + case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET: case GNUTLS_E_CLOSURE_ALERT_RECEIVED: + case GNUTLS_E_ERROR_IN_FINISHED_PACKET: return 1; case GNUTLS_E_WARNING_ALERT_RECEIVED: return 0; diff --git a/src/gnutls_errors.h b/src/gnutls_errors.h index fc4e358ff0..7a251a27b9 100644 --- a/src/gnutls_errors.h +++ b/src/gnutls_errors.h @@ -15,3 +15,5 @@ #define GNUTLS_E_UNEXPECTED_PACKET -15 #define GNUTLS_E_WARNING_ALERT_RECEIVED -16 #define GNUTLS_E_CLOSURE_ALERT_RECEIVED -17 +#define GNUTLS_E_ERROR_IN_FINISHED_PACKET -18 +#define GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET -19 diff --git a/src/gnutls_handshake.c b/src/gnutls_handshake.c index 87d66f5054..3e13252298 100644 --- a/src/gnutls_handshake.c +++ b/src/gnutls_handshake.c @@ -1,4 +1,5 @@ #include +#include #include "gnutls_int.h" #include "gnutls_errors.h" #include "debug.h" @@ -15,6 +16,77 @@ #define ERR(x, y) #endif +#define HASH_TRUE 1 +#define HASH_FALSE 0 + + +#define SERVER_MSG "server finished" +#define CLIENT_MSG "client finished" +_gnutls_send_finished( int cd, GNUTLS_STATE state) { +uint8* data; +uint8 concat[36]; /* md5+sha1 */ +int ret; + + + memset(concat, 0, 36); + memmove( concat, state->gnutls_internals.md_md5, 16); + memmove( &concat[16], state->gnutls_internals.md_sha1, 20); + + if (state->security_parameters.entity == GNUTLS_CLIENT) { + data = gnutls_PRF(state->security_parameters.master_secret, 48, + CLIENT_MSG, strlen(CLIENT_MSG), concat, 36, + 12); + } else { /* server */ + + data = gnutls_PRF(state->security_parameters.master_secret, 48, + SERVER_MSG, strlen(SERVER_MSG), concat, 36, + 12); + } + + ret = _gnutls_send_handshake( cd, state, data, 12, GNUTLS_FINISHED, HASH_FALSE); + gnutls_free(data); + + return ret; +} + +_gnutls_recv_finished( int cd, GNUTLS_STATE state) { +uint8* data, vrfy[12]; +uint8 concat[36]; /* md5+sha1 */ +int ret=0; + + memset( concat, 0, 36); + memset( vrfy, 0, 12); + memmove( concat, state->gnutls_internals.md_md5, 16); + memmove( &concat[16], state->gnutls_internals.md_sha1, 20); + + state->gnutls_internals.next_handshake_type = GNUTLS_FINISHED; + ret = gnutls_recv_int( cd, state, GNUTLS_HANDSHAKE, vrfy, 12); + if (ret<0) { + ERR("recv finished int", ret); + return ret; + } + if (ret!=12) return GNUTLS_E_ERROR_IN_FINISHED_PACKET; + + if (state->security_parameters.entity == GNUTLS_CLIENT) { + data = gnutls_PRF(state->security_parameters.master_secret, 48, + SERVER_MSG, strlen(SERVER_MSG), concat, 36, + 12); + } else { /* server */ + + data = gnutls_PRF(state->security_parameters.master_secret, 48, + CLIENT_MSG, strlen(CLIENT_MSG), concat, 36, + 12); + } + + if ( memcmp( vrfy, data, 12) != 0) ret = GNUTLS_E_ERROR_IN_FINISHED_PACKET; + + gnutls_free(data); + + return ret; +} + + + int SelectSuite( opaque ret[2], char* data, int datalen) { int x, pos=0, i,j; GNUTLS_CipherSuite *ciphers; @@ -96,7 +168,7 @@ int _gnutls_supported_compression_methods(CompressionMethod **comp) { return SUPPORTED_COMPRESSION_METHODS; } -int _gnutls_send_handshake(int cd, GNUTLS_STATE state, void* i_data, uint32 i_datasize, HandshakeType type) { +int _gnutls_send_handshake(int cd, GNUTLS_STATE state, void* i_data, uint32 i_datasize, HandshakeType type, int hash) { int ret; uint8* data; uint24 length; @@ -117,34 +189,54 @@ int _gnutls_send_handshake(int cd, GNUTLS_STATE state, void* i_data, uint32 i_da memmove( &data[pos++], &length.pint[0], 1); memmove( &data[pos++], &length.pint[1], 1); memmove( &data[pos++], &length.pint[2], 1); + if (i_datasize > 0) memmove( &data[pos], i_data, i_datasize-4); + if (hash==HASH_TRUE) { + mhash( state->gnutls_internals.td_md5, data ,i_datasize); + mhash( state->gnutls_internals.td_sha1, data, i_datasize); + } + ret = gnutls_send_int( cd, state, GNUTLS_HANDSHAKE, data, i_datasize); return ret; } -int _gnutls_recv_handshake( int cd, GNUTLS_STATE state, void* data, uint32 datasize) { +int _gnutls_recv_handshake( int cd, GNUTLS_STATE state, void* data, uint32 datasize, void* output_data, uint32 output_datasize) { int ret; uint32 length32=0; int pos=0; - char *dataptr=data; + uint8 *dataptr=data; uint24 num; + num.pint[0] = dataptr[1]; num.pint[1] = dataptr[2]; num.pint[2] = dataptr[3]; length32 = uint24touint32( num); + #ifndef WORDS_BIGENDIAN length32 = byteswap32(length32); #endif + mhash( state->gnutls_internals.td_md5, dataptr, length32 + 4); + mhash( state->gnutls_internals.td_sha1, dataptr, length32 + 4); + ret = GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET; switch(dataptr[0]) { case GNUTLS_CLIENT_HELLO: case GNUTLS_SERVER_HELLO: - ret = _gnutls_recv_hello( cd, state, &dataptr[4], length32, NULL, 0); + if (state->gnutls_internals.next_handshake_type == dataptr[0]) + ret = _gnutls_recv_hello( cd, state, &dataptr[4], length32, NULL, 0); + break; + case GNUTLS_SERVER_HELLO_DONE: + ret = 0; + break; + case GNUTLS_FINISHED: + if (output_datasize > length32) output_datasize=length32; + memmove( output_data, &dataptr[4], length32); + ret = length32; break; } @@ -152,7 +244,7 @@ int _gnutls_recv_handshake( int cd, GNUTLS_STATE state, void* data, uint32 datas } int _gnutls_send_hello_request(int cd, GNUTLS_STATE state) { - return _gnutls_send_handshake( cd, state, NULL, 0, GNUTLS_HELLO_REQUEST); + return _gnutls_send_handshake( cd, state, NULL, 0, GNUTLS_HELLO_REQUEST, HASH_FALSE); } @@ -231,7 +323,7 @@ int _gnutls_send_hello(int cd, GNUTLS_STATE state, opaque* SessionID, uint8 Sess gnutls_free(cipher_suites); gnutls_free(compression_methods); - ret = _gnutls_send_handshake( cd, state, data, datalen, GNUTLS_CLIENT_HELLO); + ret = _gnutls_send_handshake( cd, state, data, datalen, GNUTLS_CLIENT_HELLO, HASH_TRUE); gnutls_free(data); @@ -270,7 +362,7 @@ int _gnutls_send_hello(int cd, GNUTLS_STATE state, opaque* SessionID, uint8 Sess memmove( &data[pos++], &state->gnutls_internals.compression_method, 1); gcry_free(rand); - ret = _gnutls_send_handshake( cd, state, data, datalen, GNUTLS_SERVER_HELLO); + ret = _gnutls_send_handshake( cd, state, data, datalen, GNUTLS_SERVER_HELLO, HASH_TRUE); gnutls_free(data); } @@ -390,31 +482,74 @@ int ret; char* session_id; uint8 session_id_size; + state->gnutls_internals.td_md5 = mhash_init(MHASH_MD5); + state->gnutls_internals.td_sha1 = mhash_init(MHASH_SHA1); + if (state->security_parameters.entity == GNUTLS_CLIENT) { ret = _gnutls_send_hello( cd, state, NULL, 0); if (ret<0) { ERR("send hello", ret); return ret; } - /* receive the server handshake */ + + /* receive the server hello */ + state->gnutls_internals.next_handshake_type = GNUTLS_SERVER_HELLO; ret = gnutls_recv_int( cd, state, GNUTLS_HANDSHAKE, NULL, 0); if (ret<0) { ERR("recv hello", ret); return ret; } - ret = gnutls_recv_int( cd, state, GNUTLS_CHANGE_CIPHER_SPEC, NULL, 0); + + /* RECV CERTIFICATE + KEYEXCHANGE + CERTIFICATE_REQUEST */ + + /* receive the server hello done */ + state->gnutls_internals.next_handshake_type = GNUTLS_SERVER_HELLO_DONE; + ret = gnutls_recv_int( cd, state, GNUTLS_HANDSHAKE, NULL, 0); if (ret<0) { - ERR("recv ChangeCipherSpec", ret); + ERR("recv server hello done", ret); return ret; } + + /* SEND CERTIFICATE + KEYEXCHANGE + CERTIFICATE_VERIFY */ + + /* Send the CHANGE CIPHER SPEC PACKET */ ret = _gnutls_send_change_cipher_spec( cd, state); if (ret<0) { ERR("send ChangeCipherSpec", ret); return ret; } + + state->gnutls_internals.md_md5 = mhash_end( state->gnutls_internals.td_md5); + state->gnutls_internals.md_sha1 = mhash_end( state->gnutls_internals.td_sha1); + + + /* Initialize the connection state (start encryption) */ + _gnutls_connection_state_init(state); + + /* send the finished message */ + + ret = _gnutls_send_finished( cd, state); + if (ret<0) { + ERR("send Finished", ret); + return ret; + } + + ret = gnutls_recv_int( cd, state, GNUTLS_CHANGE_CIPHER_SPEC, NULL, 0); + if (ret<0) { + ERR("recv ChangeCipherSpec", ret); + return ret; + } + + ret = _gnutls_recv_finished( cd, state); + if (ret<0) { + ERR("recv finished", ret); + return ret; + } + } else { /* SERVER */ + state->gnutls_internals.next_handshake_type = GNUTLS_CLIENT_HELLO; ret = gnutls_recv_int( cd, state, GNUTLS_HANDSHAKE, NULL, 0); if (ret<0) { ERR("recv hello", ret); @@ -428,15 +563,50 @@ uint8 session_id_size; return ret; } gnutls_free(session_id); + + /* SEND CERTIFICATE + KEYEXCHANGE + CERTIFICATE_REQUEST */ + + /* send the server hello done */ + ret = _gnutls_send_handshake( cd, state, NULL, 0, GNUTLS_SERVER_HELLO_DONE, HASH_TRUE); + if (ret<0) { + ERR("send server hello done", ret); + return ret; + } + + /* RECV CERTIFICATE + KEYEXCHANGE + CERTIFICATE_VERIFY */ + + + /* Initialize the connection state (start encryption) */ + + + + ret = gnutls_recv_int( cd, state, GNUTLS_CHANGE_CIPHER_SPEC, NULL, 0); + if (ret<0) { + ERR("recv ChangeCipherSpec", ret); + return ret; + } + + _gnutls_connection_state_init(state); + state->gnutls_internals.md_md5 = mhash_end( state->gnutls_internals.td_md5); + state->gnutls_internals.md_sha1 = mhash_end( state->gnutls_internals.td_sha1); + + + ret = _gnutls_recv_finished( cd, state); + if (ret<0) { + ERR("recv finished", ret); + return ret; + } + ret = _gnutls_send_change_cipher_spec( cd, state); if (ret<0) { ERR("send ChangeCipherSpec", ret); return ret; } - ret = gnutls_recv_int( cd, state, GNUTLS_CHANGE_CIPHER_SPEC, NULL, 0); + + ret = _gnutls_send_finished( cd, state); if (ret<0) { - ERR("recv ChangeCipherSpec", ret); + ERR("recv finished", ret); return ret; } } @@ -459,3 +629,4 @@ char* rand; #endif return 0; } + diff --git a/src/gnutls_handshake.h b/src/gnutls_handshake.h index 48ef9d6db6..c39ed90706 100644 --- a/src/gnutls_handshake.h +++ b/src/gnutls_handshake.h @@ -1,9 +1,9 @@ int _gnutls_supported_ciphersuites(GNUTLS_CipherSuite **ciphers); int _gnutls_supported_compression_methods(CompressionMethod **comp); -int _gnutls_send_handshake(int cd, GNUTLS_STATE state, void* i_data, uint32 i_datasize, HandshakeType type); +int _gnutls_send_handshake(int cd, GNUTLS_STATE state, void* i_data, uint32 i_datasize, HandshakeType type, int hash); int _gnutls_send_hello_request(int cd, GNUTLS_STATE state); int _gnutls_send_hello(int cd, GNUTLS_STATE state, opaque* SessionID, uint8 SessionIDLen); int _gnutls_recv_hello(int cd, GNUTLS_STATE state, char* data, int datalen, opaque** SessionID, int SessionIDnum); int gnutls_handshake(int cd, GNUTLS_STATE state); -int _gnutls_recv_handshake( int cd, GNUTLS_STATE state, void*, uint32); +int _gnutls_recv_handshake( int cd, GNUTLS_STATE state, void*, uint32, void*, uint32); int _gnutls_generate_session_id( char** session_id, uint8* len); diff --git a/src/gnutls_int.h b/src/gnutls_int.h index 61664a9375..300b5d64b3 100644 --- a/src/gnutls_int.h +++ b/src/gnutls_int.h @@ -44,6 +44,15 @@ typedef enum AlertDescription AlertDescription; typedef enum AlertLevel AlertLevel; typedef enum ChangeCipherSpecType ChangeCipherSpecType; +enum HandshakeType { GNUTLS_HELLO_REQUEST, GNUTLS_CLIENT_HELLO, GNUTLS_SERVER_HELLO, + GNUTLS_CERTIFICATE=11, GNUTLS_SERVER_KEY_EXCHANGE, + GNUTLS_CERTIFICATE_REQUEST, GNUTLS_SERVER_HELLO_DONE, + GNUTLS_CERTIFICATE_VERIFY, GNUTLS_CLIENT_KEY_EXCHANGE, + GNUTLS_FINISHED=20 }; + +typedef enum HandshakeType HandshakeType; + + typedef struct { ChangeCipherSpecType type; } ChangeCipherSpec; @@ -125,6 +134,12 @@ typedef struct { AlertDescription last_alert; GNUTLS_CipherSuite current_cipher_suite; CompressionMethod compression_method; + /* for the handshake protocol */ + HandshakeType next_handshake_type; + MHASH td_md5; + MHASH td_sha1; + void* md_md5; + void* md_sha1; } GNUTLS_INTERNALS; typedef struct { @@ -191,13 +206,6 @@ typedef struct { /* Handshake protocol */ -enum HandshakeType { GNUTLS_HELLO_REQUEST, GNUTLS_CLIENT_HELLO, GNUTLS_SERVER_HELLO, - GNUTLS_CERTIFICATE=11, GNUTLS_SERVER_KEY_EXCHANGE, - GNUTLS_CERTIFICATE_REQUEST, GNUTLS_SERVER_HELLO_DONE, - GNUTLS_CERTIFICATE_VERIFY, GNUTLS_CLIENT_KEY_EXCHANGE, - GNUTLS_FINISHED=20 }; - -typedef enum HandshakeType HandshakeType; typedef struct { HandshakeType msg_type; @@ -232,3 +240,7 @@ typedef struct { /* functions */ int _gnutls_send_alert( int cd, GNUTLS_STATE state, AlertLevel level, AlertDescription desc); int gnutls_close(int cd, GNUTLS_STATE state); +svoid *gnutls_PRF(opaque * secret, int secret_size, uint8 * label, + int label_size, opaque * seed, int seed_size, + int total_bytes); + \ No newline at end of file diff --git a/src/gnutls_num.c b/src/gnutls_num.c index 141d43c266..4374d32ecb 100644 --- a/src/gnutls_num.c +++ b/src/gnutls_num.c @@ -1,4 +1,5 @@ #include +#include #include uint32 uint24touint32( uint24 num) { diff --git a/src/gnutls_plaintext.c b/src/gnutls_plaintext.c index 5a82106de1..b57ad97911 100644 --- a/src/gnutls_plaintext.c +++ b/src/gnutls_plaintext.c @@ -1,4 +1,5 @@ #include +#include #include "gnutls_int.h" #include "gnutls_errors.h" diff --git a/src/port.h b/src/port.h index 6c28271f0f..8e4ce24eff 100644 --- a/src/port.h +++ b/src/port.h @@ -1 +1 @@ -#define PORT 8888 \ No newline at end of file +#define PORT 5559 \ No newline at end of file diff --git a/src/serv.c b/src/serv.c index efc30f2a83..389a58a204 100644 --- a/src/serv.c +++ b/src/serv.c @@ -4,8 +4,8 @@ #include #include #include -#include "gnutls.h" -#include "port.h" +#include +#include #define SA struct sockaddr #define ERR(err,s) if(err==-1) {perror(s);return(1);} @@ -48,10 +48,21 @@ int main() - gnutls_handshake(sd, state); + ret = gnutls_handshake(sd, state); + if (ret<0) { + close(sd); + gnutls_deinit(&state); + fprintf(stderr, "Handshake has failed(%d)\n", ret); + continue; + } fprintf(stderr, "Handshake was completed\n"); ret = gnutls_send(sd, state, "hello world\n", sizeof("hello world\n")); + if (ret<0) { + close(sd); + gnutls_deinit(&state); + continue; + } fprintf(stderr, "Data was send (%d)\n", ret); gnutls_close(sd, state);