summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2001-10-20 09:10:03 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2001-10-20 09:10:03 +0000
commit2b0e6fb917697b60e3284f7adfdf9f623d022b7b (patch)
tree0267421f137751d5ef38ca9e287bf8106361e404
parent57a7554fe6101b1d5b3d98ad4be4c59efa83478f (diff)
downloadgnutls-2b0e6fb917697b60e3284f7adfdf9f623d022b7b.tar.gz
the gnutls handshake protocol can now hold it's state. Thus it
may be used in some kind of non blocking mode. Not tested at all
-rw-r--r--lib/gnutls_buffers.c4
-rw-r--r--lib/gnutls_handshake.c419
-rw-r--r--lib/gnutls_int.h6
3 files changed, 244 insertions, 185 deletions
diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c
index 70da760b4e..0b95cda5e7 100644
--- a/lib/gnutls_buffers.c
+++ b/lib/gnutls_buffers.c
@@ -224,6 +224,8 @@ void _gnutls_read_clear_buffer( GNUTLS_STATE state) {
* It does return gnutls_errno instead.
* This function reads data from the socket and keeps them in a buffer, of up to
* MAX_RECV_SIZE.
+ *
+ * sizeOfPtr should be unsigned.
*/
ssize_t _gnutls_read_buffered( int fd, GNUTLS_STATE state, opaque **iptr, size_t sizeOfPtr, int flag, ContentType recv_type)
{
@@ -234,7 +236,7 @@ ssize_t _gnutls_read_buffered( int fd, GNUTLS_STATE state, opaque **iptr, size_t
*iptr = NULL;
- if ( sizeOfPtr > MAX_RECV_SIZE || sizeOfPtr <= 0) {
+ if ( sizeOfPtr > MAX_RECV_SIZE || sizeOfPtr == 0) {
gnutls_assert(); /* internal error */
return GNUTLS_E_UNKNOWN_ERROR;
}
diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c
index ecf29d2135..638b5b40f4 100644
--- a/lib/gnutls_handshake.c
+++ b/lib/gnutls_handshake.c
@@ -1254,6 +1254,9 @@ int _gnutls_recv_hello(SOCKET cd, GNUTLS_STATE state, char *data,
*
*/
+
+#define STATE state->gnutls_internals.handshake_state
+
/**
* gnutls_handshake - This the main function in the handshake protocol.
* @cd: is a connection descriptor, as returned by socket().
@@ -1277,23 +1280,35 @@ int gnutls_handshake(SOCKET cd, GNUTLS_STATE state)
if (ret < 0)
return ret;
- return gnutls_handshake_common(cd, state);
+ ret = gnutls_handshake_common(cd, state);
+
+ if (ret < 0)
+ return ret;
+
+ STATE = STATE0;
+
+ return 0;
}
#define IMED_RET( str, ret) \
- gnutls_assert(); \
- ERR( str, ret); \
- if (ret==GNUTLS_E_AGAIN) return ret; \
- gnutls_clearHashDataBuffer(state); \
- return ret
+ if (ret < 0) { \
+ gnutls_assert(); \
+ ERR( str, ret); \
+ if (ret==GNUTLS_E_AGAIN) return ret; \
+ gnutls_clearHashDataBuffer(state); \
+ return ret; \
+ }
+
+
/*
* gnutls_handshake_client
* This function performs the client side of the handshake of the TLS/SSL protocol.
*/
+
int gnutls_handshake_client(SOCKET cd, GNUTLS_STATE state)
{
- int ret;
+ int ret = 0;
#ifdef HANDSHAKE_DEBUG
if (state->gnutls_internals.resumed_security_parameters.
@@ -1307,92 +1322,98 @@ int gnutls_handshake_client(SOCKET cd, GNUTLS_STATE state)
session_id_size));
#endif
- ret = _gnutls_send_hello(cd, state);
- if (ret < 0) {
+ if (STATE==STATE0) STATE = STATE1;
+
+ switch( STATE) {
+ case STATE1:
+ ret = _gnutls_send_hello(cd, state);
+ STATE = STATE1;
IMED_RET("send hello", ret);
- }
- /* receive the server hello */
- ret =
- _gnutls_recv_handshake(cd, state, NULL, NULL,
- GNUTLS_SERVER_HELLO, MANDATORY_PACKET);
- if (ret < 0) {
+ case STATE2:
+ /* receive the server hello */
+ ret =
+ _gnutls_recv_handshake(cd, state, NULL, NULL,
+ GNUTLS_SERVER_HELLO, MANDATORY_PACKET);
+ STATE = STATE2;
IMED_RET("recv hello", ret);
- }
- /* RECV CERTIFICATE */
- if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_recv_server_certificate(cd, state);
- if (ret < 0) {
+ case STATE3:
+ /* RECV CERTIFICATE */
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret = _gnutls_recv_server_certificate(cd, state);
+ STATE = STATE3;
IMED_RET("recv server certificate", ret);
- }
- /* receive the server key exchange */
- if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_recv_server_kx_message(cd, state);
- if (ret < 0) {
+ case STATE4:
+ /* receive the server key exchange */
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret = _gnutls_recv_server_kx_message(cd, state);
+ STATE = STATE4;
IMED_RET("recv server kx message", ret);
- }
- /* Added for SRP,
- * send the client key exchange for SRP
- */
- if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_send_client_kx_message0(cd, state);
- if (ret < 0) {
+ case STATE5:
+ /* Added for SRP,
+ * send the client key exchange for SRP
+ */
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret = _gnutls_send_client_kx_message0(cd, state);
+ STATE = STATE5;
IMED_RET("send client kx0", ret);
- }
- /* receive the server certificate request - if any
- */
+ case STATE6:
+ /* receive the server certificate request - if any
+ */
- if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_recv_server_certificate_request(cd, state);
- if (ret < 0) {
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret = _gnutls_recv_server_certificate_request(cd, state);
+ STATE = STATE6;
IMED_RET("recv server certificate request message", ret);
- }
- /* receive the server key exchange (B) (SRP only)
- */
+ case STATE7:
+ /* receive the server key exchange (B) (SRP only)
+ */
- if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_recv_server_kx_message2(cd, state);
- if (ret < 0) {
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret = _gnutls_recv_server_kx_message2(cd, state);
+ STATE = STATE7;
IMED_RET("recv server kx message2", ret);
- }
- /* receive the server hello done */
- if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
- ret =
- _gnutls_recv_handshake(cd, state, NULL, NULL,
+ case STATE8:
+ /* receive the server hello done */
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret =
+ _gnutls_recv_handshake(cd, state, NULL, NULL,
GNUTLS_SERVER_HELLO_DONE,
MANDATORY_PACKET);
- if (ret < 0) {
+ STATE = STATE8;
IMED_RET("recv server hello done", ret);
- }
- /* send our certificate - if any and if requested
- */
- if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_send_client_certificate(cd, state);
- if (ret < 0) {
+ case STATE9:
+ /* send our certificate - if any and if requested
+ */
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret = _gnutls_send_client_certificate(cd, state);
+ STATE = STATE9;
IMED_RET("send client certificate", ret);
- }
- if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_send_client_kx_message(cd, state);
- if (ret < 0) {
+ case STATE10:
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret = _gnutls_send_client_kx_message(cd, state);
+ STATE = STATE10;
IMED_RET("send client kx", ret);
- }
- /* send client certificate verify */
- if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_send_client_certificate_verify(cd, state);
- if (ret < 0) {
+ case STATE11:
+ /* send client certificate verify */
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret = _gnutls_send_client_certificate_verify(cd, state);
+ STATE = STATE11;
IMED_RET("send client certificate verify", ret);
- }
+ STATE = STATE0;
+ }
+
return 0;
}
@@ -1404,37 +1425,53 @@ static int _gnutls_send_handshake_final(SOCKET cd, GNUTLS_STATE state,
int ret = 0;
/* Send the CHANGE CIPHER SPEC PACKET */
- ret = _gnutls_send_change_cipher_spec(cd, state);
- if (ret < 0) {
- ERR("send ChangeCipherSpec", ret);
- gnutls_assert();
- return ret;
- }
- /* Initialize the connection state (start encryption) - in case of client
- */
- if (init == TRUE) {
- ret = _gnutls_connection_state_init(state);
+ if (STATE==STATE0) STATE = STATE20;
+
+ switch( STATE) {
+ case STATE20:
+ ret = _gnutls_send_change_cipher_spec(cd, state);
+ STATE = STATE20;
if (ret < 0) {
+ ERR("send ChangeCipherSpec", ret);
gnutls_assert();
return ret;
}
+
+ /* Initialize the connection state (start encryption) - in case of client
+ */
+ if (init == TRUE) {
+ ret = _gnutls_connection_state_init(state);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+ }
+
+ ret = _gnutls_write_connection_state_init(state);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ case STATE21:
+ /* send the finished message */
+ ret = _gnutls_send_finished(cd, state);
+ STATE = STATE21;
+ if (ret < 0) {
+ ERR("send Finished", ret);
+ gnutls_assert();
+ return ret;
+ }
+
+ STATE = STATE0;
}
- ret = _gnutls_write_connection_state_init(state);
- if (ret < 0) {
- gnutls_assert();
- return ret;
- }
- /* send the finished message */
- ret = _gnutls_send_finished(cd, state);
- if (ret < 0) {
- ERR("send Finished", ret);
- gnutls_assert();
- return ret;
- }
- return ret;
+
+ return 0;
}
/* This function receives the final handshake packets
+ * And executes the appropriate function to initialize the
+ * read state.
*/
static int _gnutls_recv_handshake_final(SOCKET cd, GNUTLS_STATE state,
int init)
@@ -1442,34 +1479,48 @@ static int _gnutls_recv_handshake_final(SOCKET cd, GNUTLS_STATE state,
int ret = 0;
char ch;
- ret =
- gnutls_recv_int(cd, state, GNUTLS_CHANGE_CIPHER_SPEC, -1,
- &ch, 1, 0);
- if (ret <= 0) {
- ERR("recv ChangeCipherSpec", ret);
- gnutls_assert();
- return (ret < 0) ? ret : GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
- }
- /* Initialize the connection state (start encryption) - in case of server */
- if (init == TRUE) {
- ret = _gnutls_connection_state_init(state);
+ if (STATE==STATE0) STATE = STATE30;
+
+ switch(STATE) {
+ case STATE30:
+ ret =
+ gnutls_recv_int(cd, state, GNUTLS_CHANGE_CIPHER_SPEC, -1,
+ &ch, 1, 0);
+ STATE = STATE30;
+ if (ret <= 0) {
+ ERR("recv ChangeCipherSpec", ret);
+ gnutls_assert();
+ return (ret < 0) ? ret : GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ }
+
+ /* Initialize the connection state (start encryption) - in case of server */
+ if (init == TRUE) {
+ ret = _gnutls_connection_state_init(state);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+ }
+
+ ret = _gnutls_read_connection_state_init(state);
if (ret < 0) {
gnutls_assert();
return ret;
}
+
+ case STATE31:
+ ret = _gnutls_recv_finished(cd, state);
+ STATE = STATE31;
+ if (ret < 0) {
+ ERR("recv finished", ret);
+ gnutls_assert();
+ return ret;
+ }
+ STATE = STATE0;
}
- ret = _gnutls_read_connection_state_init(state);
- if (ret < 0) {
- gnutls_assert();
- return ret;
- }
- ret = _gnutls_recv_finished(cd, state);
- if (ret < 0) {
- ERR("recv finished", ret);
- gnutls_assert();
- return ret;
- }
- return ret;
+
+
+ return 0;
}
/*
@@ -1481,89 +1532,97 @@ int gnutls_handshake_server(SOCKET cd, GNUTLS_STATE state)
{
int ret = 0;
- ret =
- _gnutls_recv_handshake(cd, state, NULL, NULL,
+ if (STATE==STATE0) STATE = STATE1;
+
+ switch( STATE) {
+ case STATE1:
+ ret =
+ _gnutls_recv_handshake(cd, state, NULL, NULL,
GNUTLS_CLIENT_HELLO, MANDATORY_PACKET);
- if (ret < 0) {
+ STATE = STATE1;
IMED_RET("recv hello", ret);
- }
-
- ret = _gnutls_send_hello(cd, state);
- if (ret < 0) {
+
+ case STATE2:
+ ret = _gnutls_send_hello(cd, state);
+ STATE = STATE2;
IMED_RET("send hello", ret);
- }
- /* NOTE: these should not be send if we are resuming */
/* SEND CERTIFICATE + KEYEXCHANGE + CERTIFICATE_REQUEST */
+ case STATE3:
+ /* NOTE: these should not be send if we are resuming */
- if (state->gnutls_internals.resumed == RESUME_FALSE)
- ret = _gnutls_send_server_certificate(cd, state);
- if (ret < 0) {
+ if (state->gnutls_internals.resumed == RESUME_FALSE)
+ ret = _gnutls_send_server_certificate(cd, state);
+ STATE = STATE3;
IMED_RET("send server certificate", ret);
- }
- /* send server key exchange (A) */
- if (state->gnutls_internals.resumed == RESUME_FALSE)
- ret = _gnutls_send_server_kx_message(cd, state);
- if (ret < 0) {
+
+ case STATE4:
+ /* send server key exchange (A) */
+ if (state->gnutls_internals.resumed == RESUME_FALSE)
+ ret = _gnutls_send_server_kx_message(cd, state);
+ STATE = STATE4;
IMED_RET("send server kx", ret);
- }
- /* Send certificate request - if requested to */
- if (state->gnutls_internals.resumed == RESUME_FALSE)
- ret = _gnutls_send_server_certificate_request(cd, state);
- if (ret < 0) {
+ case STATE5:
+ /* Send certificate request - if requested to */
+ if (state->gnutls_internals.resumed == RESUME_FALSE)
+ ret = _gnutls_send_server_certificate_request(cd, state);
+ STATE = STATE5;
IMED_RET("send server cert request", ret);
- }
-/* Added for SRP which uses a different handshake */
- /* receive the client key exchange message */
- if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_recv_client_kx_message0(cd, state);
- if (ret < 0) {
+ case STATE6:
+ /* Added for SRP which uses a different handshake */
+ /* receive the client key exchange message */
+
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret = _gnutls_recv_client_kx_message0(cd, state);
+ STATE = STATE6;
IMED_RET("recv client kx0", ret);
- }
- /* send server key exchange (B) */
- if (state->gnutls_internals.resumed == RESUME_FALSE)
- ret = _gnutls_send_server_kx_message2(cd, state);
- if (ret < 0) {
+ case STATE7:
+ /* send server key exchange (B) */
+ if (state->gnutls_internals.resumed == RESUME_FALSE)
+ ret = _gnutls_send_server_kx_message2(cd, state);
+ STATE = STATE7;
IMED_RET("send server kx2", ret);
- }
-
- /* send the server hello done */
- if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
- ret =
- _gnutls_send_handshake(cd, state, NULL, 0,
- GNUTLS_SERVER_HELLO_DONE);
- if (ret < 0) {
+ case STATE8:
+ /* send the server hello done */
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret =
+ _gnutls_send_handshake(cd, state, NULL, 0,
+ GNUTLS_SERVER_HELLO_DONE);
+ STATE = STATE8;
IMED_RET("send server hello done", ret);
- }
- /* RECV CERTIFICATE + KEYEXCHANGE + CERTIFICATE_VERIFY */
- /* receive the client certificate message */
- if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_recv_client_certificate(cd, state);
- if (ret < 0) {
+
+ /* RECV CERTIFICATE + KEYEXCHANGE + CERTIFICATE_VERIFY */
+ case STATE9:
+ /* receive the client certificate message */
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret = _gnutls_recv_client_certificate(cd, state);
+ STATE = STATE9;
IMED_RET("recv client certificate", ret);
- }
- /* receive the client key exchange message */
- if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_recv_client_kx_message(cd, state);
- if (ret < 0) {
+ case STATE10:
+ /* receive the client key exchange message */
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret = _gnutls_recv_client_kx_message(cd, state);
+ STATE = STATE10;
IMED_RET("recv client kx", ret);
- }
- /* receive the client certificate verify message */
- if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
- ret =
- _gnutls_recv_client_certificate_verify_message(cd,
+ case STATE11:
+ /* receive the client certificate verify message */
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret =
+ _gnutls_recv_client_certificate_verify_message(cd,
state);
- if (ret < 0) {
+ STATE = STATE11;
IMED_RET("recv client certificate verify", ret);
- }
+ STATE = STATE0; /* finished thus clear state */
+ }
+
return 0;
}
@@ -1580,23 +1639,17 @@ int gnutls_handshake_common(SOCKET cd, GNUTLS_STATE state)
/* if we are a client resuming - or we are a server not resuming */
ret = _gnutls_recv_handshake_final(cd, state, TRUE);
- if (ret < 0) {
- IMED_RET("recv handshake final", ret);
- }
+ IMED_RET("recv handshake final", ret);
+
ret = _gnutls_send_handshake_final(cd, state, FALSE);
- if (ret < 0) {
- IMED_RET( "send handshake final", ret);
- }
+ IMED_RET( "send handshake final", ret);
} else { /* if we are a client not resuming - or we are a server resuming */
ret = _gnutls_send_handshake_final(cd, state, TRUE);
- if (ret < 0) {
- IMED_RET("send handshake final 2", ret);
- }
+ IMED_RET("send handshake final 2", ret);
+
ret = _gnutls_recv_handshake_final(cd, state, FALSE);
- if (ret < 0) {
- IMED_RET("recv handshake final 2", ret);
- }
+ IMED_RET("recv handshake final 2", ret);
}
if (state->security_parameters.entity == GNUTLS_SERVER) {
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index a4b9828c47..b1ca4009b3 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -99,6 +99,10 @@ typedef enum CertificateStatus { GNUTLS_CERT_TRUSTED=1, GNUTLS_CERT_NOT_TRUSTED,
typedef enum CertificateRequest { GNUTLS_CERT_REQUEST=1, GNUTLS_CERT_REQUIRE } CertificateRequest;
typedef enum CloseRequest { GNUTLS_SHUT_RDWR=0, GNUTLS_SHUT_WR=1 } CloseRequest;
+typedef enum HandshakeState { STATE0=0, STATE1, STATE2, STATE3, STATE4, STATE5,
+ STATE6, STATE7, STATE8, STATE9, STATE10, STATE11, STATE20=20, STATE21,
+ STATE30=30, STATE31 } HandshakeState;
+
typedef 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,
@@ -318,7 +322,7 @@ typedef struct {
gnutls_datum hash_buffer; /* used to keep all handshake messages */
gnutls_datum buffer_handshake; /* this is a buffer that holds the current handshake message */
ResumableSession resumable; /* TRUE or FALSE - if we can resume that session */
-/* jmp_buf handshake_nb_state; /* holds
+ HandshakeState handshake_state; /* holds
* a number which indicates where
* the handshake procedure has been
* interrupted. If it is 0 then