#include #include "ssl_locl.h" #include #include #include #include //#define DEBUG static const SSL_METHOD *spp_get_client_method(int ver); static const SSL_METHOD *spp_get_client_method(int ver) { if (ver == SPP_VERSION) return SPP_client_method(); return NULL; } IMPLEMENT_spp_meth_func(SPP_VERSION, SPP_client_method, ssl_undefined_function, spp_connect, spp_get_client_method) int spp_connect(SSL *s) { BUF_MEM *buf=NULL; SPP_PROXY* proxy=NULL; unsigned long Time=(unsigned long)time(NULL); void (*cb)(const SSL *ssl,int type,int val)=NULL; int ret= -1,i; int new_state,state,skip=0; /* Matteo -- START */ struct timeval currTime; // keep current time struct timeval prevTime; // keep previous time (to compute time passed) struct timeval originTime; // keep previous time (to compute time passed) /* Matteo -- END*/ RAND_add(&Time,sizeof(Time),0); ERR_clear_error(); clear_sys_error(); if (s->info_callback != NULL) cb=s->info_callback; else if (s->ctx->info_callback != NULL) cb=s->ctx->info_callback; s->in_handshake++; if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s); #ifndef OPENSSL_NO_HEARTBEATS /* If we're awaiting a HeartbeatResponse, pretend we * already got and don't await it anymore, because * Heartbeats don't make sense during handshakes anyway. */ if (s->tlsext_hb_pending) { s->tlsext_hb_pending = 0; s->tlsext_hb_seq++; } #endif for (;;) { state=s->state; switch(s->state) { case SSL_ST_RENEGOTIATE: SSLerr(SSL_F_SSL3_CONNECT, ERR_R_INTERNAL_ERROR); ret = -1; goto end; case SSL_ST_BEFORE: case SSL_ST_CONNECT: case SSL_ST_BEFORE|SSL_ST_CONNECT: case SSL_ST_OK|SSL_ST_CONNECT: // Initialize timers gettimeofday(&currTime, NULL); gettimeofday(&prevTime, NULL); gettimeofday(&originTime, NULL); // Log #ifdef DEBUG log_time("Connecting\n", &currTime, &prevTime, &originTime); #endif s->server=0; /* We are the client */ s->proxy=0; s->proxy_id=1; if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1); if ((s->version & 0xff00 ) != 0x0600) { /* SPP major version is 6 */ SSLerr(SSL_F_SSL3_CONNECT, ERR_R_INTERNAL_ERROR); ret = -1; goto end; } s->version=SPP_VERSION; s->type=SSL_ST_CONNECT; if (s->init_buf == NULL) { if ((buf=BUF_MEM_new()) == NULL) { ret= -1; goto end; } if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH)) { ret= -1; goto end; } s->init_buf=buf; buf=NULL; } if (!ssl3_setup_buffers(s)) { ret= -1; goto end; } /* setup buffing BIO */ if (!ssl_init_wbio_buffer(s,0)) { ret= -1; goto end; } if (!spp_generate_slice_keys(s)) { ret = -1; goto end; } /* don't push the buffering BIO quite yet */ ssl3_init_finished_mac(s); s->state=SSL3_ST_CW_CLNT_HELLO_A; s->ctx->stats.sess_connect++; s->init_num=0; break; case SSL3_ST_CW_CLNT_HELLO_A: case SSL3_ST_CW_CLNT_HELLO_B: // Logging with time information #ifdef DEBUG log_time("Sending client hello\n", &currTime, &prevTime, &originTime); #endif s->shutdown=0; ret=ssl3_client_hello(s); if (ret <= 0) goto end; s->state=SSL3_ST_CR_SRVR_HELLO_A; s->init_num=0; /* turn on buffering for the next lot of output */ if (s->bbio != s->wbio) s->wbio=BIO_push(s->bbio,s->wbio); break; case SSL3_ST_CR_SRVR_HELLO_A: case SSL3_ST_CR_SRVR_HELLO_B: ret=ssl3_get_server_hello(s); // Logging with time information #ifdef DEBUG log_time("Received server hello\n", &currTime, &prevTime, &originTime); #endif if (ret <= 0) goto end; s->state=SSL3_ST_CR_CERT_A; s->init_num=0; break; case SSL3_ST_CR_CERT_A: case SSL3_ST_CR_CERT_B: ret=ssl3_get_server_certificate(s); // Logging with time information #ifdef DEBUG log_time("Received server certificate\n", &currTime, &prevTime, &originTime); #endif if (ret <= 0) goto end; s->state=SSL3_ST_CR_KEY_EXCH_A; s->init_num=0; break; case SSL3_ST_CR_KEY_EXCH_A: case SSL3_ST_CR_KEY_EXCH_B: ret=ssl3_get_key_exchange(s); // Logging with time information #ifdef DEBUG log_time("Received server key exchange\n", &currTime, &prevTime, &originTime); #endif if (ret <= 0) goto end; s->state=SSL3_ST_CR_CERT_REQ_A; s->init_num=0; /* at this point we check that we have the * required stuff from the server */ if (!ssl3_check_cert_and_algorithm(s)) { ret= -1; goto end; } break; case SSL3_ST_CR_CERT_REQ_A: case SSL3_ST_CR_CERT_REQ_B: ret=ssl3_get_certificate_request(s); // Logging with time information #ifdef DEBUG log_time("Done certificate request\n", &currTime, &prevTime, &originTime); #endif if (ret <= 0) goto end; s->state=SSL3_ST_CR_SRVR_DONE_A; s->init_num=0; break; case SSL3_ST_CR_SRVR_DONE_A: case SSL3_ST_CR_SRVR_DONE_B: ret=ssl3_get_server_done(s); // Logging with time information #ifdef DEBUG log_time("Received server done\n", &currTime, &prevTime, &originTime); #endif if (ret <= 0) goto end; /*#ifndef OPENSSL_NO_SRP if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) { if ((ret = SRP_Calc_A_param(s))<=0) { SSLerr(SSL_F_SSL3_CONNECT,SSL_R_SRP_A_CALC); ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_INTERNAL_ERROR); goto end; } } #endif*/ if (s->s3->tmp.cert_req) s->state=SSL3_ST_CW_CERT_A; else { proxy = spp_get_next_proxy(s, proxy, 0); if (proxy == NULL) { s->state=SSL3_ST_CW_KEY_EXCH_A; } else { s->state=SPP_ST_CR_PRXY_CERT_A; } } s->init_num=0; break; case SSL3_ST_CW_CERT_A: case SSL3_ST_CW_CERT_B: case SSL3_ST_CW_CERT_C: case SSL3_ST_CW_CERT_D: // Logging with time information #ifdef DEBUG log_time("Sending client certificate\n", &currTime, &prevTime, &originTime); #endif ret=ssl3_send_client_certificate(s); if (ret <= 0) goto end; proxy = spp_get_next_proxy(s, proxy, 0); if (proxy == NULL) { s->state=SSL3_ST_CW_KEY_EXCH_A; } else { s->state=SPP_ST_CR_PRXY_CERT_A; } s->init_num=0; break; case SPP_ST_CR_PRXY_CERT_A: case SPP_ST_CR_PRXY_CERT_B: // Logging with time information #ifdef DEBUG log_time("Waiting for proxy certificate\n", &currTime, &prevTime, &originTime); #endif ret=spp_get_proxy_certificate(s, proxy); gettimeofday(&currTime, NULL); // Logging with time information #ifdef DEBUG log_time("Received proxy certificate\n", &currTime, &prevTime, &originTime); #endif if (ret <= 0) goto end; s->state=SPP_ST_CR_PRXY_KEY_EXCH_A; s->init_num=0; break; /* Receive the hello messages from the proxies now. */ case SPP_ST_CR_PRXY_KEY_EXCH_A: case SPP_ST_CR_PRXY_KEY_EXCH_B: ret=spp_get_proxy_key_exchange(s, proxy); // Logging with time information #ifdef DEBUG log_time("Received proxy key exchange\n", &currTime, &prevTime, &originTime); #endif if (ret <= 0) goto end; s->state=SPP_ST_CR_PRXY_DONE_A; s->init_num=0; break; case SPP_ST_CR_PRXY_DONE_A: case SPP_ST_CR_PRXY_DONE_B: ret=spp_get_proxy_done(s, proxy); // Logging with time information #ifdef DEBUG log_time("Received proxy done\n", &currTime, &prevTime, &originTime); #endif if (ret <= 0) goto end; proxy = spp_get_next_proxy(s, proxy, 0); if (proxy == NULL) { s->state=SSL3_ST_CW_KEY_EXCH_A; } else { /* Go back and read the next proxy */ s->state=SPP_ST_CR_PRXY_CERT_A; } s->init_num=0; break; case SSL3_ST_CW_KEY_EXCH_A: case SSL3_ST_CW_KEY_EXCH_B: // Logging with time information #ifdef DEBUG log_time("Sending client key exchange\n", &currTime, &prevTime, &originTime); #endif ret=ssl3_send_client_key_exchange(s); if (ret <= 0) goto end; s->state=SPP_ST_CW_PRXY_MAT_A; //s->s3->change_cipher_spec=0; s->init_num=0; break; /* Send the proxy key material. */ case SPP_ST_CW_PRXY_MAT_A: case SPP_ST_CW_PRXY_MAT_B: // Logging with time information #ifdef DEBUG log_time("Sending proxy key material\n", &currTime, &prevTime, &originTime); #endif for (i = 0; i < s->proxies_len; i++) { ret=spp_send_proxy_key_material(s, s->proxies[i]); if (ret <= 0) goto end; s->state = SPP_ST_CW_PRXY_MAT_A; s->init_num=0; } ret=spp_send_end_key_material_client(s); //s->s3->tmp.next_state=SPP_ST_CR_PRXY_MAT_A; //s->state=SSL3_ST_CW_FLUSH; s->state=SSL3_ST_CW_CHANGE_A; //s->s3->change_cipher_spec=0; s->init_num=0; break; case SPP_ST_CR_PRXY_MAT_A: case SPP_ST_CR_PRXY_MAT_B: // Logging with time information #ifdef DEBUG log_time("Receiving proxy key material\n", &currTime, &prevTime, &originTime); #endif for (i = s->proxies_len-1; i >= 0; i--) { ret=spp_get_proxy_key_material(s, s->proxies[i]); if (ret <= 0) goto end; s->state = SPP_ST_CR_PRXY_MAT_A; s->init_num=0; } ret=spp_get_end_key_material_client(s); // Logging with time information #ifdef DEBUG log_time("Received proxy key material\n", &currTime, &prevTime, &originTime); #endif if (ret <= 0) goto end; #ifndef OPENSSL_NO_TLSEXT /* Allow NewSessionTicket if ticket expected */ if (s->tlsext_ticket_expected) s->state=SSL3_ST_CR_SESSION_TICKET_A; else #endif s->state=SSL3_ST_CR_FINISHED_A; s->s3->change_cipher_spec=0; s->init_num=0; break; case SSL3_ST_CW_CHANGE_A: case SSL3_ST_CW_CHANGE_B: // Logging with time information #ifdef DEBUG log_time("Sending change cipher state\n", &currTime, &prevTime, &originTime); #endif ret=ssl3_send_change_cipher_spec(s,SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B); if (ret <= 0) goto end; #if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG) s->state=SSL3_ST_CW_FINISHED_A; #else if (s->s3->next_proto_neg_seen) s->state=SSL3_ST_CW_NEXT_PROTO_A; else s->state=SSL3_ST_CW_FINISHED_A; #endif s->init_num=0; s->session->cipher=s->s3->tmp.new_cipher; #ifdef OPENSSL_NO_COMP s->session->compress_meth=0; #else if (s->s3->tmp.new_compression == NULL) s->session->compress_meth=0; else s->session->compress_meth= s->s3->tmp.new_compression->id; #endif if (!s->method->ssl3_enc->setup_key_block(s)) { ret= -1; goto end; } if (!s->method->ssl3_enc->change_cipher_state(s,SSL3_CHANGE_CIPHER_CLIENT_WRITE)) { ret= -1; goto end; } /* Set up all */ break; #if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) case SSL3_ST_CW_NEXT_PROTO_A: case SSL3_ST_CW_NEXT_PROTO_B: ret=ssl3_send_next_proto(s); if (ret <= 0) goto end; s->state=SSL3_ST_CW_FINISHED_A; break; #endif case SSL3_ST_CW_FINISHED_A: case SSL3_ST_CW_FINISHED_B: // Logging with time information #ifdef DEBUG log_time("Sending client finished\n", &currTime, &prevTime, &originTime); #endif ret=ssl3_send_finished(s, SSL3_ST_CW_FINISHED_A,SSL3_ST_CW_FINISHED_B, s->method->ssl3_enc->client_finished_label, s->method->ssl3_enc->client_finished_label_len); if (ret <= 0) goto end; s->s3->flags |= SSL3_FLAGS_CCS_OK; s->state=SSL3_ST_CW_FLUSH; /* clear flags */ s->s3->flags&= ~SSL3_FLAGS_POP_BUFFER; if (s->hit) { s->s3->tmp.next_state=SSL_ST_OK; if (s->s3->flags & SSL3_FLAGS_DELAY_CLIENT_FINISHED) { s->state=SSL_ST_OK; s->s3->flags|=SSL3_FLAGS_POP_BUFFER; s->s3->delay_buf_pop_ret=0; } } else { s->s3->tmp.next_state=SPP_ST_CR_PRXY_MAT_A; } // Store the values for end-to-end integrity checking if (spp_init_integrity_st(s) <= 0) goto end; s->init_num=0; break; #ifndef OPENSSL_NO_TLSEXT case SSL3_ST_CR_SESSION_TICKET_A: case SSL3_ST_CR_SESSION_TICKET_B: #ifdef DEBUG log_time("Receiving session ticket\n", &currTime, &prevTime, &originTime); #endif ret=ssl3_get_new_session_ticket(s); if (ret <= 0) goto end; s->state=SSL3_ST_CR_FINISHED_A; s->init_num=0; break; case SSL3_ST_CR_CERT_STATUS_A: case SSL3_ST_CR_CERT_STATUS_B: #ifdef DEBUG log_time("Receiving cert status\n", &currTime, &prevTime, &originTime); #endif ret=ssl3_get_cert_status(s); if (ret <= 0) goto end; s->state=SSL3_ST_CR_KEY_EXCH_A; s->init_num=0; break; #endif case SSL3_ST_CR_FINISHED_A: case SSL3_ST_CR_FINISHED_B: // Logging with time information #ifdef DEBUG log_time("Receiving server finished\n", &currTime, &prevTime, &originTime); #endif s->s3->flags |= SSL3_FLAGS_CCS_OK; ret=ssl3_get_finished(s,SSL3_ST_CR_FINISHED_A, SSL3_ST_CR_FINISHED_B); if (ret <= 0) goto end; if (s->hit) s->state=SSL3_ST_CW_CHANGE_A; else s->state=SSL_ST_OK; s->init_num=0; /* Setup the slices now that we have the necessary state. */ ret = spp_init_slices_st(s, SSL3_CHANGE_CIPHER_CLIENT_WRITE); if (ret <= 0) goto end; ret = spp_init_slices_st(s, SSL3_CHANGE_CIPHER_CLIENT_READ); if (ret <= 0) goto end; break; case SSL3_ST_CW_FLUSH: s->rwstate=SSL_WRITING; if (BIO_flush(s->wbio) <= 0) { ret= -1; goto end; } s->rwstate=SSL_NOTHING; s->state=s->s3->tmp.next_state; break; case SSL_ST_OK: #ifdef DEBUG log_time("Handshake OK\n", &currTime, &prevTime, &originTime); #endif /* clean a few things up */ ssl3_cleanup_key_block(s); if (s->init_buf != NULL) { BUF_MEM_free(s->init_buf); s->init_buf=NULL; } /* If we are not 'joining' the last two packets, * remove the buffering now */ if (!(s->s3->flags & SSL3_FLAGS_POP_BUFFER)) ssl_free_wbio_buffer(s); /* else do it later in ssl3_write */ s->init_num=0; s->renegotiate=0; s->new_session=0; ssl_update_cache(s,SSL_SESS_CACHE_CLIENT); if (s->hit) s->ctx->stats.sess_hit++; ret=1; /* s->server=0; */ s->handshake_func=spp_connect; s->ctx->stats.sess_connect_good++; if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1); goto end; /* break; */ default: SSLerr(SSL_F_SSL3_CONNECT,SSL_R_UNKNOWN_STATE); ret= -1; goto end; /* break; */ } /* did we do anything */ if (!s->s3->tmp.reuse_message && !skip) { if (s->debug) { if ((ret=BIO_flush(s->wbio)) <= 0) goto end; } if ((cb != NULL) && (s->state != state)) { new_state=s->state; s->state=state; cb(s,SSL_CB_CONNECT_LOOP,1); s->state=new_state; } } skip=0; } end: // Logging with time information #ifdef DEBUG log_time("Handshake end\n", &currTime, &prevTime, &originTime); #endif s->in_handshake--; if (buf != NULL) BUF_MEM_free(buf); if (cb != NULL) cb(s,SSL_CB_CONNECT_EXIT,ret); return(ret); }