示例#1
0
文件: bio_ssl.c 项目: lullajd/openssl
static long ssl_ctrl(BIO *b, int cmd, long num, void *ptr)
{
    SSL **sslp, *ssl;
    BIO_SSL *bs, *dbs;
    BIO *dbio, *bio;
    long ret = 1;
    BIO *next;

    bs = BIO_get_data(b);
    next = BIO_next(b);
    ssl = bs->ssl;
    if ((ssl == NULL) && (cmd != BIO_C_SET_SSL))
        return 0;
    switch (cmd) {
    case BIO_CTRL_RESET:
        SSL_shutdown(ssl);

        if (ssl->handshake_func == ssl->method->ssl_connect)
            SSL_set_connect_state(ssl);
        else if (ssl->handshake_func == ssl->method->ssl_accept)
            SSL_set_accept_state(ssl);

        if (!SSL_clear(ssl)) {
            ret = 0;
            break;
        }

        if (next != NULL)
            ret = BIO_ctrl(next, cmd, num, ptr);
        else if (ssl->rbio != NULL)
            ret = BIO_ctrl(ssl->rbio, cmd, num, ptr);
        else
            ret = 1;
        break;
    case BIO_CTRL_INFO:
        ret = 0;
        break;
    case BIO_C_SSL_MODE:
        if (num)                /* client mode */
            SSL_set_connect_state(ssl);
        else
            SSL_set_accept_state(ssl);
        break;
    case BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT:
        ret = bs->renegotiate_timeout;
        if (num < 60)
            num = 5;
        bs->renegotiate_timeout = (unsigned long)num;
        bs->last_time = (unsigned long)time(NULL);
        break;
    case BIO_C_SET_SSL_RENEGOTIATE_BYTES:
        ret = bs->renegotiate_count;
        if ((long)num >= 512)
            bs->renegotiate_count = (unsigned long)num;
        break;
    case BIO_C_GET_SSL_NUM_RENEGOTIATES:
        ret = bs->num_renegotiates;
        break;
    case BIO_C_SET_SSL:
        if (ssl != NULL) {
            ssl_free(b);
            if (!ssl_new(b))
                return 0;
        }
        BIO_set_shutdown(b, num);
        ssl = (SSL *)ptr;
        bs->ssl = ssl;
        bio = SSL_get_rbio(ssl);
        if (bio != NULL) {
            if (next != NULL)
                BIO_push(bio, next);
            BIO_set_next(b, bio);
            BIO_up_ref(bio);
        }
        BIO_set_init(b, 1);
        break;
    case BIO_C_GET_SSL:
        if (ptr != NULL) {
            sslp = (SSL **)ptr;
            *sslp = ssl;
        } else
            ret = 0;
        break;
    case BIO_CTRL_GET_CLOSE:
        ret = BIO_get_shutdown(b);
        break;
    case BIO_CTRL_SET_CLOSE:
        BIO_set_shutdown(b, (int)num);
        break;
    case BIO_CTRL_WPENDING:
        ret = BIO_ctrl(ssl->wbio, cmd, num, ptr);
        break;
    case BIO_CTRL_PENDING:
        ret = SSL_pending(ssl);
        if (ret == 0)
            ret = BIO_pending(ssl->rbio);
        break;
    case BIO_CTRL_FLUSH:
        BIO_clear_retry_flags(b);
        ret = BIO_ctrl(ssl->wbio, cmd, num, ptr);
        BIO_copy_next_retry(b);
        break;
    case BIO_CTRL_PUSH:
        if ((next != NULL) && (next != ssl->rbio)) {
            /*
             * We are going to pass ownership of next to the SSL object...but
             * we don't own a reference to pass yet - so up ref
             */
            BIO_up_ref(next);
            SSL_set_bio(ssl, next, next);
        }
        break;
    case BIO_CTRL_POP:
        /* Only detach if we are the BIO explicitly being popped */
        if (b == ptr) {
            /* This will clear the reference we obtained during push */
            SSL_set_bio(ssl, NULL, NULL);
        }
        break;
    case BIO_C_DO_STATE_MACHINE:
        BIO_clear_retry_flags(b);

        BIO_set_retry_reason(b, 0);
        ret = (int)SSL_do_handshake(ssl);

        switch (SSL_get_error(ssl, (int)ret)) {
        case SSL_ERROR_WANT_READ:
            BIO_set_flags(b, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY);
            break;
        case SSL_ERROR_WANT_WRITE:
            BIO_set_flags(b, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY);
            break;
        case SSL_ERROR_WANT_CONNECT:
            BIO_set_flags(b, BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY);
            BIO_set_retry_reason(b, BIO_get_retry_reason(next));
            break;
        case SSL_ERROR_WANT_X509_LOOKUP:
            BIO_set_retry_special(b);
            BIO_set_retry_reason(b, BIO_RR_SSL_X509_LOOKUP);
            break;
        default:
            break;
        }
        break;
    case BIO_CTRL_DUP:
        dbio = (BIO *)ptr;
        dbs = BIO_get_data(dbio);
        SSL_free(dbs->ssl);
        dbs->ssl = SSL_dup(ssl);
        dbs->num_renegotiates = bs->num_renegotiates;
        dbs->renegotiate_count = bs->renegotiate_count;
        dbs->byte_count = bs->byte_count;
        dbs->renegotiate_timeout = bs->renegotiate_timeout;
        dbs->last_time = bs->last_time;
        ret = (dbs->ssl != NULL);
        break;
    case BIO_C_GET_FD:
        ret = BIO_ctrl(ssl->rbio, cmd, num, ptr);
        break;
    case BIO_CTRL_SET_CALLBACK:
        ret = 0; /* use callback ctrl */
        break;
    case BIO_CTRL_GET_CALLBACK:
        {
            void (**fptr) (const SSL *xssl, int type, int val);

            fptr = (void (**)(const SSL *xssl, int type, int val))ptr;
            *fptr = SSL_get_info_callback(ssl);
        }
        break;
    default:
        ret = BIO_ctrl(ssl->rbio, cmd, num, ptr);
        break;
    }
    return ret;
}
示例#2
0
int ssl23_connect(SSL *s)
	{
	BUF_MEM *buf=NULL;
	unsigned long Time=(unsigned long)time(NULL);
	void (*cb)(const SSL *ssl,int type,int val)=NULL;
	int ret= -1;
	int new_state,state;

	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); 

	for (;;)
		{
		state=s->state;

		switch(s->state)
			{
		case SSL_ST_BEFORE:
		case SSL_ST_CONNECT:
		case SSL_ST_BEFORE|SSL_ST_CONNECT:
		case SSL_ST_OK|SSL_ST_CONNECT:

			if (s->session != NULL)
				{
				SSLerr(SSL_F_SSL23_CONNECT,SSL_R_SSL23_DOING_SESSION_ID_REUSE);
				ret= -1;
				goto end;
				}
			s->server=0;
			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);

			/* s->version=TLS1_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; }

			ssl3_init_finished_mac(s);

			s->state=SSL23_ST_CW_CLNT_HELLO_A;
			s->ctx->stats.sess_connect++;
			s->init_num=0;
			break;

		case SSL23_ST_CW_CLNT_HELLO_A:
		case SSL23_ST_CW_CLNT_HELLO_B:

			s->shutdown=0;
			ret=ssl23_client_hello(s);
			if (ret <= 0) goto end;
			s->state=SSL23_ST_CR_SRVR_HELLO_A;
			s->init_num=0;

			break;

		case SSL23_ST_CR_SRVR_HELLO_A:
		case SSL23_ST_CR_SRVR_HELLO_B:
			ret=ssl23_get_server_hello(s);
			if (ret >= 0) cb=NULL;
			goto end;
			/* break; */

		default:
			SSLerr(SSL_F_SSL23_CONNECT,SSL_R_UNKNOWN_STATE);
			ret= -1;
			goto end;
			/* break; */
			}

		if (s->debug) { (void)BIO_flush(s->wbio); }

		if ((cb != NULL) && (s->state != state))
			{
			new_state=s->state;
			s->state=state;
			cb(s,SSL_CB_CONNECT_LOOP,1);
			s->state=new_state;
			}
		}
end:
	s->in_handshake--;
	if (buf != NULL)
		BUF_MEM_free(buf);
	if (cb != NULL)
		cb(s,SSL_CB_CONNECT_EXIT,ret);
	return(ret);
	}
int dtls_get_data (int s, SSL_CTX *ctx)
{
	char *buf = NULL;
	fd_set readfds;
	int ret = 1, width = 0;
	int i = 0;
	SSL *con = NULL;
	BIO *sbio = NULL;
	int bufsize = BUFSIZ;
	bio_err = BIO_new_fp (stderr, BIO_NOCLOSE);
	bio_s_out = BIO_new_fp (stderr, BIO_NOCLOSE);

	
	if ((buf = OPENSSL_malloc (bufsize)) == NULL)
	{
		BIO_printf (bio_err, "out of memory\n");
		goto ERR;
	}

	if (con == NULL) 
	{
		con = SSL_new(ctx);
	}
	SSL_clear (con);

	if (SSL_version (con) == DTLS1_VERSION)
	{
		struct timeval timeout;

		sbio = BIO_new_dgram (s, BIO_NOCLOSE);

		timeout.tv_sec = 5;
		timeout.tv_usec = 0;
		BIO_ctrl (sbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);
			
		timeout.tv_sec = 5;
		timeout.tv_usec = 0;
		BIO_ctrl (sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout);

		
			/* want to do MTU discovery */
		BIO_ctrl (sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL);

	        /* turn on cookie exchange */
        	SSL_set_options (con, SSL_OP_COOKIE_EXCHANGE);
//		fprintf (stderr, "%s: %s(): DTLSv1 Initialization done\n", __FILE__, __func__);
	}

	SSL_set_bio (con, sbio, sbio);
	SSL_set_accept_state (con);
	/* SSL_set_fd(con,s); */

	width = s + 1;
	for (;;)
	{
		int read_from_terminal;
		int read_from_sslcon;

		read_from_terminal = 0;
		read_from_sslcon = SSL_pending (con);

		if (!read_from_sslcon)
		{
			struct timeval tv;
			FD_ZERO(&readfds);
			FD_SET(s, &readfds);
			tv.tv_sec = 1;
			tv.tv_usec = 0;
			i = select(width, (void *)&readfds, NULL, NULL, &tv);
			if (i < 0)
			{
				continue;
			}
			if (FD_ISSET (s, &readfds))
			{
				read_from_sslcon = 1;
			}
			else
			{
				ret = 2;
				goto shut;
			}
		}
		if (read_from_sslcon)
		{
			if (!SSL_is_init_finished(con))
			{
				i = init_ssl_connection(con);
			
				if (i < 0)
				{
					ret = 0;
					goto ERR;
				}
				else if (i == 0)
				{
					ret = 1;
					goto ERR;
				}
			}
			else
			{
AGAIN:	
				i = SSL_read (con, (char *) buf, bufsize);
				switch (SSL_get_error (con, i))
				{
					case SSL_ERROR_NONE:
						write (fileno (stdout), buf, (unsigned int) i);
						if (SSL_pending(con)) 
						{
							fprintf (stderr, "%s: %s(): Some more seems to be coming... "\
								"letz wait for that\n", __FILE__, __func__);
							goto AGAIN;
						}
						else
							fprintf (stderr, "%s(): Hey, itz all over boss... do finishing "\
								"ceremony\n", __func__);
						ret = 0;
						goto ERR;
					case SSL_ERROR_WANT_WRITE:
					case SSL_ERROR_WANT_READ:
					case SSL_ERROR_WANT_X509_LOOKUP:
						BIO_printf(bio_s_out,"Read BLOCK\n");
						break;
					case SSL_ERROR_SYSCALL:
					case SSL_ERROR_SSL:
						BIO_printf(bio_s_out,"ERROR\n");
						ERR_print_errors(bio_err);
						ret = 1;
						goto ERR;
					case SSL_ERROR_ZERO_RETURN:
						BIO_printf(bio_s_out,"\nDONE\n");
						ret = 0;
						goto ERR;
				}
			}
		}
	}
ERR:
	if (0 == ret)
	{
		char temp [] = "ACK from SERVER: READ SUCCESSFULLY DONE\n";
		for (;;)
		{
			i = SSL_write (con, temp, strlen (temp));

			switch (SSL_get_error (con, i))
			{
				case SSL_ERROR_NONE:
					if (SSL_pending (con))
						break;
					else
						goto WRITEDONE;
				case SSL_ERROR_WANT_WRITE:
				case SSL_ERROR_WANT_READ:
				case SSL_ERROR_WANT_X509_LOOKUP:
					BIO_printf (bio_s_out, "Write BLOCK\n");
					break;
				case SSL_ERROR_SYSCALL:
				case SSL_ERROR_SSL:
					BIO_printf (bio_s_out, "ERROR\n");
					ERR_print_errors (bio_err);
					ret = 1;
					goto WRITEDONE;
				case SSL_ERROR_ZERO_RETURN:
					BIO_printf (bio_s_out, "\nDONE\n");
					ret = 1;
					goto WRITEDONE;
			}
		}
	}
WRITEDONE:
#ifdef DEBUG
	BIO_printf (bio_s_out, "shutting down SSL\n");
	print_stats (bio_s_out, ctx);
#endif
#if 1
	SSL_set_shutdown (con, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
#else
	SSL_shutdown(con);
#endif
shut:
	if (con != NULL) SSL_free (con);
	if (2 != ret)
		BIO_printf(bio_s_out,"CONNECTION CLOSED\n");

	if (buf != NULL)
	{
		OPENSSL_cleanse (buf, bufsize);
		OPENSSL_free (buf);
	}

	if ((ret >= 0) && (2 != ret))
		BIO_printf (bio_s_out, "ACCEPT\n");
	return(ret);
}
示例#4
0
文件: ssl.c 项目: backcn/wrk
status ssl_close(connection *c) {
    SSL_shutdown(c->ssl);
    SSL_clear(c->ssl);
    return OK;
}
示例#5
0
文件: d1_clnt.c 项目: rskinner/oossl
int dtls1_connect(SSL *s)
	{
	BUF_MEM *buf=NULL;
	unsigned long Time=(unsigned long)time(NULL);
	void (*cb)(const SSL *ssl,int type,int val)=NULL;
	int ret= -1;
	int new_state,state,skip=0;
#ifndef OPENSSL_NO_SCTP
	unsigned char sctpauthkey[64];
	char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
#endif

	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_SCTP
	/* Notify SCTP BIO socket to enter handshake
	 * mode and prevent stream identifier other
	 * than 0. Will be ignored if no SCTP is used.
	 */
	BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE, s->in_handshake, NULL);
#endif

#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)
		{
		dtls1_stop_timer(s);
		s->tlsext_hb_pending = 0;
		s->tlsext_hb_seq++;
		}
#endif

	for (;;)
		{
		state=s->state;

		switch(s->state)
			{
		case SSL_ST_RENEGOTIATE:
			s->renegotiate=1;
			s->state=SSL_ST_CONNECT;
			s->ctx->stats.sess_connect_renegotiate++;
			/* break */
		case SSL_ST_BEFORE:
		case SSL_ST_CONNECT:
		case SSL_ST_BEFORE|SSL_ST_CONNECT:
		case SSL_ST_OK|SSL_ST_CONNECT:

			s->server=0;
			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);

			if ((s->version & 0xff00 ) != (DTLS1_VERSION & 0xff00) &&
			    (s->version & 0xff00 ) != (DTLS1_BAD_VER & 0xff00))
				{
				SSLerr(SSL_F_DTLS1_CONNECT, ERR_R_INTERNAL_ERROR);
				ret = -1;
				goto end;
				}
				
			/* s->version=SSL3_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; }

			/* don't push the buffering BIO quite yet */

			s->state=SSL3_ST_CW_CLNT_HELLO_A;
			s->ctx->stats.sess_connect++;
			s->init_num=0;
			/* mark client_random uninitialized */
			memset(s->s3->client_random,0,sizeof(s->s3->client_random));
			s->d1->send_cookie = 0;
			s->hit = 0;
			break;

#ifndef OPENSSL_NO_SCTP
		case DTLS1_SCTP_ST_CR_READ_SOCK:

			if (BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s)))
			{
				s->s3->in_read_app_data=2;
				s->rwstate=SSL_READING;
				BIO_clear_retry_flags(SSL_get_rbio(s));
				BIO_set_retry_read(SSL_get_rbio(s));
				ret = -1;
				goto end;
			}

			s->state=s->s3->tmp.next_state;
			break;

		case DTLS1_SCTP_ST_CW_WRITE_SOCK:
			/* read app data until dry event */

			ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s));
			if (ret < 0) goto end;

			if (ret == 0)
			{
				s->s3->in_read_app_data=2;
				s->rwstate=SSL_READING;
				BIO_clear_retry_flags(SSL_get_rbio(s));
				BIO_set_retry_read(SSL_get_rbio(s));
				ret = -1;
				goto end;
			}

			s->state=s->d1->next_state;
			break;
#endif

		case SSL3_ST_CW_CLNT_HELLO_A:
		case SSL3_ST_CW_CLNT_HELLO_B:

			s->shutdown=0;

			/* every DTLS ClientHello resets Finished MAC */
			ssl3_init_finished_mac(s);

			dtls1_start_timer(s);
			ret=ssl3_client_hello(s);
			if (ret <= 0) goto end;

			if ( s->d1->send_cookie)
				{
				s->state=SSL3_ST_CW_FLUSH;
				s->s3->tmp.next_state=SSL3_ST_CR_SRVR_HELLO_A;
				}
			else
				s->state=SSL3_ST_CR_SRVR_HELLO_A;

			s->init_num=0;

#ifndef OPENSSL_NO_SCTP
			/* Disable buffering for SCTP */
			if (!BIO_dgram_is_sctp(SSL_get_wbio(s)))
				{
#endif
				/* turn on buffering for the next lot of output */
				if (s->bbio != s->wbio)
					s->wbio=BIO_push(s->bbio,s->wbio);
#ifndef OPENSSL_NO_SCTP
				}
#endif

			break;

		case SSL3_ST_CR_SRVR_HELLO_A:
		case SSL3_ST_CR_SRVR_HELLO_B:
			ret=ssl3_get_server_hello(s);
			if (ret <= 0) goto end;
			else
				{
				if (s->hit)
					{
#ifndef OPENSSL_NO_SCTP
					/* Add new shared key for SCTP-Auth,
					 * will be ignored if no SCTP used.
					 */
					snprintf((char*) labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
					         DTLS1_SCTP_AUTH_LABEL);

					SSL_export_keying_material(s, sctpauthkey,
					                           sizeof(sctpauthkey), labelbuffer,
					                           sizeof(labelbuffer), NULL, 0, 0);

					BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
							 sizeof(sctpauthkey), sctpauthkey);
#endif

					s->state=SSL3_ST_CR_FINISHED_A;
					}
				else
					s->state=DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A;
				}
			s->init_num=0;
			break;

		case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A:
		case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B:

			ret = dtls1_get_hello_verify(s);
			if ( ret <= 0)
				goto end;
			dtls1_stop_timer(s);
			if ( s->d1->send_cookie) /* start again, with a cookie */
				s->state=SSL3_ST_CW_CLNT_HELLO_A;
			else
				s->state = SSL3_ST_CR_CERT_A;
			s->init_num = 0;
			break;

		case SSL3_ST_CR_CERT_A:
		case SSL3_ST_CR_CERT_B:
#ifndef OPENSSL_NO_TLSEXT
			ret=ssl3_check_finished(s);
			if (ret <= 0) goto end;
			if (ret == 2)
				{
				s->hit = 1;
				if (s->tlsext_ticket_expected)
					s->state=SSL3_ST_CR_SESSION_TICKET_A;
				else
					s->state=SSL3_ST_CR_FINISHED_A;
				s->init_num=0;
				break;
				}
#endif
			/* Check if it is anon DH or PSK */
			if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
			    !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
				{
				ret=ssl3_get_server_certificate(s);
				if (ret <= 0) goto end;
#ifndef OPENSSL_NO_TLSEXT
				if (s->tlsext_status_expected)
					s->state=SSL3_ST_CR_CERT_STATUS_A;
				else
					s->state=SSL3_ST_CR_KEY_EXCH_A;
				}
			else
				{
				skip = 1;
				s->state=SSL3_ST_CR_KEY_EXCH_A;
				}
#else
				}
			else
				skip=1;

			s->state=SSL3_ST_CR_KEY_EXCH_A;
#endif
			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);
			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);
			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);
			if (ret <= 0) goto end;
			dtls1_stop_timer(s);
			if (s->s3->tmp.cert_req)
				s->s3->tmp.next_state=SSL3_ST_CW_CERT_A;
			else
				s->s3->tmp.next_state=SSL3_ST_CW_KEY_EXCH_A;
			s->init_num=0;

#ifndef OPENSSL_NO_SCTP			
			if (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
			    state == SSL_ST_RENEGOTIATE)
				s->state=DTLS1_SCTP_ST_CR_READ_SOCK;
			else
#endif			
			s->state=s->s3->tmp.next_state;
			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:
			dtls1_start_timer(s);
			ret=ssl3_send_client_certificate(s);
			if (ret <= 0) goto end;
			s->state=SSL3_ST_CW_KEY_EXCH_A;
			s->init_num=0;
			break;

		case SSL3_ST_CW_KEY_EXCH_A:
		case SSL3_ST_CW_KEY_EXCH_B:
			dtls1_start_timer(s);
			ret=ssl3_send_client_key_exchange(s);
			if (ret <= 0) goto end;

#ifndef OPENSSL_NO_SCTP
			/* Add new shared key for SCTP-Auth,
			 * will be ignored if no SCTP used.
			 */
			snprintf((char*) labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
			         DTLS1_SCTP_AUTH_LABEL);

			SSL_export_keying_material(s, sctpauthkey,
			                           sizeof(sctpauthkey), labelbuffer,
			                           sizeof(labelbuffer), NULL, 0, 0);

			BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
					 sizeof(sctpauthkey), sctpauthkey);
#endif

			/* EAY EAY EAY need to check for DH fix cert
			 * sent back */
			/* For TLS, cert_req is set to 2, so a cert chain
			 * of nothing is sent, but no verify packet is sent */
			if (s->s3->tmp.cert_req == 1)
				{
				s->state=SSL3_ST_CW_CERT_VRFY_A;
				}
			else
				{
#ifndef OPENSSL_NO_SCTP
				if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
					{
					s->d1->next_state=SSL3_ST_CW_CHANGE_A;
					s->state=DTLS1_SCTP_ST_CW_WRITE_SOCK;
					}
				else
#endif
					s->state=SSL3_ST_CW_CHANGE_A;
				s->s3->change_cipher_spec=0;
				}

			s->init_num=0;
			break;

		case SSL3_ST_CW_CERT_VRFY_A:
		case SSL3_ST_CW_CERT_VRFY_B:
			dtls1_start_timer(s);
			ret=ssl3_send_client_verify(s);
			if (ret <= 0) goto end;
#ifndef OPENSSL_NO_SCTP
			if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
			{
				s->d1->next_state=SSL3_ST_CW_CHANGE_A;
				s->state=DTLS1_SCTP_ST_CW_WRITE_SOCK;
			}
			else
#endif
				s->state=SSL3_ST_CW_CHANGE_A;
			s->init_num=0;
			s->s3->change_cipher_spec=0;
			break;

		case SSL3_ST_CW_CHANGE_A:
		case SSL3_ST_CW_CHANGE_B:
			if (!s->hit)
				dtls1_start_timer(s);
			ret=dtls1_send_change_cipher_spec(s,
				SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B);
			if (ret <= 0) goto end;

			s->state=SSL3_ST_CW_FINISHED_A;
			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;
				}
			
#ifndef OPENSSL_NO_SCTP
				if (s->hit)
					{
					/* Change to new shared key of SCTP-Auth,
					 * will be ignored if no SCTP used.
					 */
					BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, 0, NULL);
					}
#endif

			dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
			break;

		case SSL3_ST_CW_FINISHED_A:
		case SSL3_ST_CW_FINISHED_B:
			if (!s->hit)
				dtls1_start_timer(s);
			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->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;
#ifndef OPENSSL_NO_SCTP
				if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
					{
						s->d1->next_state = s->s3->tmp.next_state;
						s->s3->tmp.next_state=DTLS1_SCTP_ST_CW_WRITE_SOCK;
					}
#endif
				if (s->s3->flags & SSL3_FLAGS_DELAY_CLIENT_FINISHED)
					{
					s->state=SSL_ST_OK;
#ifndef OPENSSL_NO_SCTP
					if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
						{
							s->d1->next_state = SSL_ST_OK;
							s->state=DTLS1_SCTP_ST_CW_WRITE_SOCK;
						}
#endif
					s->s3->flags|=SSL3_FLAGS_POP_BUFFER;
					s->s3->delay_buf_pop_ret=0;
					}
				}
			else
				{
#ifndef OPENSSL_NO_SCTP
				/* Change to new shared key of SCTP-Auth,
				 * will be ignored if no SCTP used.
				 */
				BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, 0, NULL);
#endif

#ifndef OPENSSL_NO_TLSEXT
				/* Allow NewSessionTicket if ticket expected */
				if (s->tlsext_ticket_expected)
					s->s3->tmp.next_state=SSL3_ST_CR_SESSION_TICKET_A;
				else
#endif
				
				s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A;
				}
			s->init_num=0;
			break;

#ifndef OPENSSL_NO_TLSEXT
		case SSL3_ST_CR_SESSION_TICKET_A:
		case SSL3_ST_CR_SESSION_TICKET_B:
			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:
			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:
			s->d1->change_cipher_spec_ok = 1;
			ret=ssl3_get_finished(s,SSL3_ST_CR_FINISHED_A,
				SSL3_ST_CR_FINISHED_B);
			if (ret <= 0) goto end;
			dtls1_stop_timer(s);

			if (s->hit)
				s->state=SSL3_ST_CW_CHANGE_A;
			else
				s->state=SSL_ST_OK;

#ifndef OPENSSL_NO_SCTP
			if (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
				state == SSL_ST_RENEGOTIATE)
				{
				s->d1->next_state=s->state;
				s->state=DTLS1_SCTP_ST_CW_WRITE_SOCK;
				}
#endif

			s->init_num=0;
			break;

		case SSL3_ST_CW_FLUSH:
			s->rwstate=SSL_WRITING;
			if (BIO_flush(s->wbio) <= 0)
				{
				/* If the write error was fatal, stop trying */
				if (!BIO_should_retry(s->wbio))
					{
					s->rwstate=SSL_NOTHING;
					s->state=s->s3->tmp.next_state;
					}
				
				ret= -1;
				goto end;
				}
			s->rwstate=SSL_NOTHING;
			s->state=s->s3->tmp.next_state;
			break;

		case SSL_ST_OK:
			/* clean a few things up */
			ssl3_cleanup_key_block(s);

#if 0
			if (s->init_buf != NULL)
				{
				BUF_MEM_free(s->init_buf);
				s->init_buf=NULL;
				}
#endif

			/* 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=dtls1_connect;
			s->ctx->stats.sess_connect_good++;

			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1);

			/* done with handshaking */
			s->d1->handshake_read_seq  = 0;
			s->d1->next_handshake_write_seq = 0;
			goto end;
			/* break; */
			
		default:
			SSLerr(SSL_F_DTLS1_CONNECT,SSL_R_UNKNOWN_STATE);
			ret= -1;
			goto end;
			/* break; */
			}
示例#6
0
static int ssl_do(struct st_VioSSLFd *ptr, Vio *vio, long timeout,
                  ssl_handshake_func_t func,
                  unsigned long *ssl_errno_holder)
{
  int r;
  SSL *ssl;
  my_socket sd= mysql_socket_getfd(vio->mysql_socket);
  DBUG_ENTER("ssl_do");
  DBUG_PRINT("enter", ("ptr: 0x%lx, sd: %d  ctx: 0x%lx",
                       (long) ptr, sd, (long) ptr->ssl_context));

  if (!(ssl= SSL_new(ptr->ssl_context)))
  {
    DBUG_PRINT("error", ("SSL_new failure"));
    *ssl_errno_holder= ERR_get_error();
    DBUG_RETURN(1);
  }
  DBUG_PRINT("info", ("ssl: 0x%lx timeout: %ld", (long) ssl, timeout));
  SSL_clear(ssl);
  SSL_SESSION_set_timeout(SSL_get_session(ssl), timeout);
  SSL_set_fd(ssl, sd);
#if !defined(HAVE_YASSL) && defined(SSL_OP_NO_COMPRESSION)
  SSL_set_options(ssl, SSL_OP_NO_COMPRESSION);
#endif

  /*
    Since yaSSL does not support non-blocking send operations, use
    special transport functions that properly handles non-blocking
    sockets. These functions emulate the behavior of blocking I/O
    operations by waiting for I/O to become available.
  */
#ifdef HAVE_YASSL
  /* Set first argument of the transport functions. */
  yaSSL_transport_set_ptr(ssl, vio);
  /* Set functions to use in order to send and receive data. */
  yaSSL_transport_set_recv_function(ssl, yassl_recv);
  yaSSL_transport_set_send_function(ssl, yassl_send);
#endif

  if ((r= ssl_handshake_loop(vio, ssl, func, ssl_errno_holder)) < 1)
  {
    DBUG_PRINT("error", ("SSL_connect/accept failure"));
    SSL_free(ssl);
    DBUG_RETURN(1);
  }

  /*
    Connection succeeded. Install new function handlers,
    change type, set sd to the fd used when connecting
    and set pointer to the SSL structure
  */
  if (vio_reset(vio, VIO_TYPE_SSL, SSL_get_fd(ssl), ssl, 0))
    DBUG_RETURN(1);

#ifndef DBUG_OFF
  {
    /* Print some info about the peer */
    X509 *cert;
    char buf[512];

    DBUG_PRINT("info",("SSL connection succeeded"));
    DBUG_PRINT("info",("Using cipher: '%s'" , SSL_get_cipher_name(ssl)));

    if ((cert= SSL_get_peer_certificate (ssl)))
    {
      DBUG_PRINT("info",("Peer certificate:"));
      X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
      DBUG_PRINT("info",("\t subject: '%s'", buf));
      X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf));
      DBUG_PRINT("info",("\t issuer: '%s'", buf));
      X509_free(cert);
    }
    else
      DBUG_PRINT("info",("Peer does not have certificate."));

    if (SSL_get_shared_ciphers(ssl, buf, sizeof(buf)))
    {
      DBUG_PRINT("info",("shared_ciphers: '%s'", buf));
    }
    else
      DBUG_PRINT("info",("no shared ciphers!"));
  }
#endif

  DBUG_RETURN(0);
}
示例#7
0
int ssl23_accept(SSL *s)
	{
	BUF_MEM *buf;
	unsigned long Time=(unsigned long)time(NULL);
	void (*cb)(const SSL *ssl,int type,int val)=NULL;
	int ret= -1;
	int new_state,state;

	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); 

	for (;;)
		{
		state=s->state;

		switch(s->state)
			{
		case SSL_ST_BEFORE:
		case SSL_ST_ACCEPT:
		case SSL_ST_BEFORE|SSL_ST_ACCEPT:
		case SSL_ST_OK|SSL_ST_ACCEPT:

			s->server=1;
			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);

			/* s->version=SSL3_VERSION; */
			s->type=SSL_ST_ACCEPT;

			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;
				}

			ssl3_init_finished_mac(s);

			s->state=SSL23_ST_SR_CLNT_HELLO_A;
			s->ctx->stats.sess_accept++;
			s->init_num=0;
			break;

		case SSL23_ST_SR_CLNT_HELLO_A:
		case SSL23_ST_SR_CLNT_HELLO_B:

			s->shutdown=0;
			ret=ssl23_get_client_hello(s);
			if (ret >= 0) cb=NULL;
			goto end;
			/* break; */

		default:
			SSLerr(SSL_F_SSL23_ACCEPT,SSL_R_UNKNOWN_STATE);
			ret= -1;
			goto end;
			/* break; */
			}

		if ((cb != NULL) && (s->state != state))
			{
			new_state=s->state;
			s->state=state;
			cb(s,SSL_CB_ACCEPT_LOOP,1);
			s->state=new_state;
			}
		}
end:
	s->in_handshake--;
	if (cb != NULL)
		cb(s,SSL_CB_ACCEPT_EXIT,ret);
	return(ret);
	}
示例#8
0
int main(void)
{

	BIO *sbio;
	SSL *ssl;
	SSL_CTX *ctx;
	int ret = 0;


	SSL_library_init();
	RAND_load_file("/dev/urandom", 1024);

	ctx = setup_client_ctx();


	/* Now doing standard connect stuff */

	char sendline[MAXLINE + 1], recvline[MAXLINE + 1];
	char password[MAXLINE + 1];


	int sockfd;
	struct sockaddr_in servaddr;

	char **pptr;
	//********** You can change. Put any values here *******
	char *hname = "smtp.gmail.com";

	//*******************************************************

	char str[50];
	struct hostent *hptr;
	if ((hptr = gethostbyname(hname)) == NULL) {
		fprintf(stderr, " gethostbyname error for host: %s: %s",
			hname, hstrerror(h_errno));
		exit(1);
	}
	printf("hostname: %s\n", hptr->h_name);
	if (hptr->h_addrtype == AF_INET
	    && (pptr = hptr->h_addr_list) != NULL) {
		printf("address: %s\n",
		       inet_ntop(hptr->h_addrtype, *pptr, str,
				 sizeof(str)));
	} else {
		fprintf(stderr, "Error call inet_ntop \n");
	}

	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;

	servaddr.sin_port = htons(25);
	inet_pton(AF_INET, str, &servaddr.sin_addr);

	connect(sockfd, (SA *) & servaddr, sizeof(servaddr));


	fprintf(stderr, "%s\n", socket_read(sockfd,recvline));
        socket_write(sockfd,"EHLO big.mchirico.org\r\n");
	fprintf(stderr, "ehlo response:%s<-\n", socket_read(sockfd,recvline));


	socket_write(sockfd, "STARTTLS\r\n");
	fprintf(stderr, "response to starttls:%s<-\n", socket_read(sockfd,recvline));


	sbio = BIO_new_socket(sockfd, BIO_NOCLOSE);
	ssl = SSL_new(ctx);
	SSL_set_bio(ssl, sbio, sbio);
	SSL_set_connect_state(ssl);



	/* Circuit Breaker - NO encrypted connection */
	if (SSL_do_handshake(ssl) == 1) {
		fprintf(stderr, "SSL_do_handshake(ssl)=%d\n", 1);
	} else {
		fprintf(stderr, "SSL handshake error= %d\n",
			SSL_get_error(ssl, ret));
		fprintf(stderr,
			"Cannot establish an encrypted connection\nExiting\n\n");
		return -1;
	}



        SSL_socket_write(ssl,"EHLO mchirico.org\r\n");
        fprintf(stderr,"k: %s",SSL_socket_read(ssl,recvline));



	get_password("password_smtp_64", password, MAXLINE);

	snprintf(sendline, MAXLINE, "AUTH PLAIN %s\r\n", password); 
        fprintf(stderr,"password: ->%s<-\n",password);
        SSL_socket_write(ssl,sendline);
	fprintf(stderr, "login res: %s<-",SSL_socket_read(ssl,recvline));


        SSL_socket_write(ssl,"MAIL FROM: <*****@*****.**>\r\n");
	fprintf(stderr, "2:%s",SSL_socket_read(ssl,recvline));


        SSL_socket_write(ssl,"RCPT TO: <*****@*****.**>\r\n");
	fprintf(stderr, "3:%s", SSL_socket_read(ssl,recvline));
        
        SSL_socket_write(ssl,"RCPT TO: <*****@*****.**>\r\n");
	fprintf(stderr, "3:%s", SSL_socket_read(ssl,recvline));

        SSL_socket_write(ssl,
          "DATA\r\nFrom: [email protected]\r\n"
          "To: [email protected]\r\n"
          "To: [email protected]\r\n"
          "subject: Example using tlssmtp.c\r\n"
          "\r\nTest Send from tlssmtp.c"
          "\r\n.\r\n");
	fprintf(stderr, "4:%s", SSL_socket_read(ssl,recvline));


	fprintf(stderr, "5:%s", SSL_socket_read(ssl,recvline));

	SSL_shutdown(ssl);
	SSL_clear(ssl);

	fprintf(stderr, "SSL Connection closed\n");

	SSL_free(ssl);
	SSL_CTX_free(ctx);


	return 0;

}
示例#9
0
/* This function is called on a socket file descriptor once the connection has been
 * established and we're ready to negotiate SSL.  If the SSL handshake fails for some
 * reason (such as the host on the other end not using SSL), it will return 0 for
 * failure.  Success returns 1.
 */
static int FinishConnection(TCLinkCon *c, int sd)
{
	int ssl_connected, is_error, errcode, res;
	X509 *server_cert;
	time_t start, remaining;
	fd_set in, out, err;
	struct timeval tv;

	/* check if socket has connected successfully */
	int val;
	int /*socklen_t*/ size = 4;
	getsockopt(sd, SOL_SOCKET, SO_ERROR, (char*)&val, &size);
	if (val != 0)
		return 0;

	SSL_clear(c->ssl);

	SSL_set_fd(c->ssl, sd);

	ssl_connected = 0;
	is_error = 0;
	start = time(0);

	while (!ssl_connected && !is_error)
	{

		remaining = 5 - (time(0) - start);
		if (remaining <= 0) {
			is_error = 1;
			break;
		}

		res = SSL_connect(c->ssl);

		ssl_connected = ((res == 1) && SSL_is_init_finished(c->ssl));

		if (!ssl_connected)
		{
			FD_ZERO(&in); FD_SET((unsigned)sd, &in);
			FD_ZERO(&out); FD_SET((unsigned)sd, &out);
			FD_ZERO(&err); FD_SET((unsigned)sd, &err);
			/* the documentation does not suggest that both error types occur at the same time so
			 * the retry logic will consume all the outstanding events
			 * we do not actually use oob data, but if it is sent, it is treated as an error all the
			 * same
			 */
			errcode = SSL_get_error(c->ssl, res);
			switch (errcode)
			{
				case SSL_ERROR_NONE:
					/* no error, we should have a connection, check again */
					break;

				case SSL_ERROR_WANT_READ:
					/* no error, just wait for more data */
					tv.tv_sec = remaining; tv.tv_usec = 0;
					/* posix-2001 says the function will modify the appropriate descriptors */
					if (select(sd+1, &in, NULL, &err, &tv) < 0 ||
						FD_ISSET((unsigned)sd, &err)
						)
						is_error = 1;
					break;
				case SSL_ERROR_WANT_WRITE:
					/* no error, just wait for more data */
					tv.tv_sec = remaining; tv.tv_usec = 0;
					if (select(sd+1, NULL, &out, &err, &tv) < 0 ||
						FD_ISSET((unsigned)sd, &err)
						)
						is_error = 1;
					break;
				case SSL_ERROR_ZERO_RETURN: /* peer closed the connection */
				case SSL_ERROR_SSL:         /* error in SSL handshake */
				default:
					is_error = 1;
			}
		}
	}

	if (is_error) {
		return 0;
	}
   
	
#ifdef WIN32
	u_long param = 0;
	ioctlsocket(sd, FIONBIO, &param);           // make the socket blocking again 
#else
	fcntl(sd, F_SETFL, 0);           /* make the socket blocking again */
#endif
	
	/* verify that server certificate is authentic */
	server_cert = SSL_get_peer_certificate(c->ssl);
	if (!server_cert) {
		X509_free(server_cert);
		return 0;
	}
	if (c->validate_cert && c->validate_cert(0, server_cert) != 0)
	{
		X509_free(server_cert);
		return 0;
	}
	X509_free(server_cert);

	return 1;
}
示例#10
0
/*++
 * Function:	Get_Server_conn
 *
 * Purpose:	When a client login attempt is made, fetch a usable server
 *              connection descriptor.  This means that either we reuse an
 *              existing ICD, or we open a new one.  Hide that abstraction from
 *              the caller...
 *
 * Parameters:	ptr to username string
 *		ptr to password string
 *              const ptr to client hostname or IP string (for logging only)
 *              in_port_t, client port number (for logging only)
 *              unsigned char - flag to indicate that the client sent the
 *                              password as a string literal.
 *
 * Returns:	ICD * on success
 *              NULL on failure
 *
 * Authors:	Dave McMurtrie <*****@*****.**>
 *
 * Credit:      Major SSL additions by Ken Murchison <*****@*****.**>
 *
 *--
 */
extern ICD_Struct *Get_Server_conn( char *Username, 
				    char *Password,
				    const char *ClientAddr,
				    in_port_t sin_port,
				    unsigned char LiteralPasswd )
{
    char *fn = "Get_Server_conn()";
    unsigned int HashIndex;
    ICC_Struct *HashEntry = NULL;
    char SendBuf[BUFSIZE];
    unsigned int BufLen = BUFSIZE - 1;
    char md5pw[MD5_DIGEST_LENGTH];
    char *tokenptr;
    char *endptr;
    char *last;
    ICC_Struct *ICC_Active;
    ICC_Struct *ICC_tptr;
    ITD_Struct Server;
    int rc;
    unsigned int Expiration;

    EVP_MD_CTX mdctx;
    int md_len;

    Expiration = PC_Struct.cache_expiration_time;
    memset( &Server, 0, sizeof Server );
    
    /* need to md5 the passwd regardless, so do that now */
    EVP_DigestInit(&mdctx, EVP_md5());
    EVP_DigestUpdate(&mdctx, Password, strlen(Password));
    EVP_DigestFinal(&mdctx, md5pw, &md_len);
    
    /* see if we have a reusable connection available */
    ICC_Active = NULL;
    HashIndex = Hash( Username, HASH_TABLE_SIZE );
    
    LockMutex( &mp );
        
    /*
     * Now we just iterate through the linked list at this hash index until
     * we either find the string we're looking for or we find a NULL.
     */
    for ( HashEntry = ICC_HashTable[ HashIndex ]; 
	  HashEntry; 
	  HashEntry = HashEntry->next )
    {
	if ( ( strcmp( Username, HashEntry->username ) == 0 ) &&
	     ( HashEntry->logouttime > 1 ) )
	{
	    ICC_Active = HashEntry;
	    /*
	     * we found this username in our hash table.  Need to know if
	     * the password matches.
	     */
	    if ( memcmp( md5pw, ICC_Active->hashedpw, sizeof md5pw ) )
	    {
		syslog( LOG_NOTICE, "%s: Unable to reuse server sd [%d] for user '%s' (%s:%d) because password doesn't match.", fn, ICC_Active->server_conn->sd, Username, ClientAddr, sin_port );
		ICC_Active->logouttime = 1;
	    }
	    else
	    {
		/*
		 * We found a matching password on an inactive server socket.
		 * We can use this guy.  Before we release the mutex, set the
		 * logouttime such that we mark this connection as "active"
		 * again.
		 */
		ICC_Active->logouttime = 0;
	
		/*
		 * The fact that we have this stored in a table as an open
		 * server socket doesn't really mean that it's open.  The
		 * server could've closed it on us.
		 * We need a speedy way to make sure this is still open.
		 * We'll set the fd to non-blocking and try to read from it.
		 * If we get a zero back, the connection is closed.  If we get
		 * EWOULDBLOCK (or some data) we know it's still open.  If we
		 * do read data, make sure we read all the data so we "drain"
		 * any puss that may be left on this socket.
		 */
		fcntl( ICC_Active->server_conn->sd, F_SETFL,
		       fcntl( ICC_Active->server_conn->sd, F_GETFL, 0) | O_NONBLOCK );
		
		while ( ( rc = IMAP_Read( ICC_Active->server_conn, Server.ReadBuf, 
				     sizeof Server.ReadBuf ) ) > 0 );
		
		if ( !rc )
		{
		    syslog(LOG_NOTICE, "%s: Unable to reuse server sd [%d] for user '%s' (%s:%d).  Connection closed by server.", fn, ICC_Active->server_conn->sd, Username, ClientAddr, sin_port );
		    ICC_Active->logouttime = 1;
		    continue;
		}
	    
		if ( errno != EWOULDBLOCK )
		{
		    syslog(LOG_NOTICE, "%s: Unable to reuse server sd [%d] for user '%s' (%s:%d). IMAP_read() error: %s", fn, ICC_Active->server_conn->sd, Username, ClientAddr, sin_port, strerror( errno ) );
		    ICC_Active->logouttime = 1;
		    continue;
		}
		
		fcntl( ICC_Active->server_conn->sd, F_SETFL, 
		       fcntl( ICC_Active->server_conn->sd, F_GETFL, 0) & ~O_NONBLOCK );
		
		/* now release the mutex and return the sd to the caller */
		UnLockMutex( &mp );

		/*
		 * We're reusing an existing server socket.  There are a few
		 * counters we have to deal with.
		 */
		IMAPCount->RetainedServerConnections--;
		IMAPCount->InUseServerConnections++;
		IMAPCount->TotalServerConnectionsReused++;
		
		if ( IMAPCount->InUseServerConnections >
		     IMAPCount->PeakInUseServerConnections )
		    IMAPCount->PeakInUseServerConnections = IMAPCount->InUseServerConnections;
	    
		syslog(LOG_INFO, "LOGIN: '******' (%s:%d) on existing sd [%d]", Username, ClientAddr, sin_port, ICC_Active->server_conn->sd );
		return( ICC_Active->server_conn );
	    }
	}
    }
    
    
    UnLockMutex( &mp );
    
    /*
     * We don't have an active connection for this user, or the password
     * didn't match.
     * Open a connection to the IMAP server so we can attempt to login 
     */
    Server.conn = ( ICD_Struct * ) malloc( sizeof ( ICD_Struct ) );
    memset( Server.conn, 0, sizeof ( ICD_Struct ) );
    Server.conn->sd = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );
    if ( Server.conn->sd == -1 )
    {
	syslog(LOG_INFO, "LOGIN: '******' (%s:%d) failed: Unable to open server socket: %s", Username, ClientAddr, sin_port, strerror( errno ) );
	goto fail;
    }

    if ( PC_Struct.send_tcp_keepalives )
    {
	int onoff = 1;
	setsockopt( Server.conn->sd, SOL_SOCKET, SO_KEEPALIVE, &onoff, sizeof onoff );
    }
    
    if ( connect( Server.conn->sd, (struct sockaddr *)&ISD.srv, 
		  sizeof(ISD.srv) ) == -1 )
    {
	syslog(LOG_INFO, "LOGIN: '******' (%s:%d) failed: Unable to connect to IMAP server: %s", Username, ClientAddr, sin_port, strerror( errno ) );
	goto fail;
    }
    
    
    /* Read & throw away the banner line from the server */
    
    if ( IMAP_Line_Read( &Server ) == -1 )
    {
	syslog(LOG_INFO, "LOGIN: '******' (%s:%d) failed: No banner line received from IMAP server", Username, ClientAddr, sin_port );
	goto fail;
    }

    /*
     * Sanity check.  We don't deal with literal responses in the
     * banner string.
     */
    if ( Server.LiteralBytesRemaining )
    {
	syslog(LOG_ERR, "%s: Unexpected string literal in server banner response.", fn );
	goto fail;
	
    }
    

    /*
     * Do STARTTLS if necessary.
     */
#if HAVE_LIBSSL
    if ( PC_Struct.login_disabled || PC_Struct.force_tls )
    {
	snprintf( SendBuf, BufLen, "S0001 STARTTLS\r\n" );
	if ( IMAP_Write( Server.conn, SendBuf, strlen(SendBuf) ) == -1 )
	{
	    syslog(LOG_INFO, "STARTTLS failed: IMAP_Write() failed attempting to send STARTTLS command to IMAP server: %s", strerror( errno ) );
	    goto fail;
	}

	/*
	 * Read the server response
	 */
	if ( ( rc = IMAP_Line_Read( &Server ) ) == -1 )
	{
	    syslog(LOG_INFO, "STARTTLS failed: No response from IMAP server after sending STARTTLS command" );
	    goto fail;
	}

	if ( Server.LiteralBytesRemaining )
	{
	    syslog(LOG_ERR, "%s: Unexpected string literal in server response.", fn );
	    goto fail;
	
	}
	
    
	/*
	 * Try to match up the tag in the server response to the client tag.
	 */
	endptr = Server.ReadBuf + rc;
    
	tokenptr = memtok( Server.ReadBuf, endptr, &last );
    
	if ( !tokenptr )
	{
	    /* 
	     * no tokens found in server response?  Not likely, but we still
	     * have to check.
	     */
	    syslog(LOG_INFO, "STARTTLS failed: server response to STARTTLS command contained no tokens." );
	    goto fail;
	}
    
	if ( memcmp( (const void *)tokenptr, (const void *)"S0001", 
		     strlen( tokenptr ) ) )
	{
	    /* 
	     * non-matching tag read back from the server... Lord knows what this
	     * is, so we'll fail.
	     */
	    syslog(LOG_INFO, "STARTTLS failed: server response to STARTTLS command contained non-matching tag." );
	    goto fail;
	}
    
	/*
	 * Now that we've matched the tags up, see if the response was 'OK'
	 */
	tokenptr = memtok( NULL, endptr, &last );
    
	if ( !tokenptr )
	{
	    /* again, not likely but we still have to check... */
	    syslog(LOG_INFO, "STARTTLS failed: Malformed server response to STARTTLS command" );
	    goto fail;
	}
    
	if ( memcmp( (const void *)tokenptr, "OK", 2 ) )
	{
	    /*
	     * If the server sent back a "NO" or "BAD", we can look at the actual
	     * server logs to figure out why.  We don't have to break our ass here
	     * putting the string back together just for the sake of logging.
	     */
	    syslog(LOG_INFO, "STARTTLS failed: non-OK server response to STARTTLS command" );
	    goto fail;
	}
    
	Server.conn->tls = SSL_new( tls_ctx );
	if ( Server.conn->tls == NULL )
	{
	    syslog(LOG_INFO, "STARTTLS failed: SSL_new() failed" );
	    goto fail;
	}
	    
	SSL_clear( Server.conn->tls );
	rc = SSL_set_fd( Server.conn->tls, Server.conn->sd );
	if ( rc == 0 )
	{
	    syslog(LOG_INFO, "STARTTLS failed: SSL_set_fd() failed: %d",
		   SSL_get_error( Server.conn->tls, rc ) );
	    goto fail;
	}

	SSL_set_connect_state( Server.conn->tls );
	rc = SSL_connect( Server.conn->tls );
	if ( rc <= 0 )
	{
	    syslog(LOG_INFO, "STARTTLS failed: SSL_connect() failed, %d: %s",
		   SSL_get_error( Server.conn->tls, rc ), SSLerrmessage() );
	    goto fail;
	}

	/* XXX Should we grab the session id for later reuse? */
    }
#endif /* HAVE_LIBSSL */


    /*
     * Send the login command off to the IMAP server.  Have to treat a literal
     * password different.
     */
    if ( LiteralPasswd )
    {
	snprintf( SendBuf, BufLen, "A0001 LOGIN %s {%d}\r\n", 
		  Username, strlen( Password ) );
	if ( IMAP_Write( Server.conn, SendBuf, strlen(SendBuf) ) == -1 )
	{
	    syslog(LOG_INFO, "LOGIN: '******' (%s:%d) failed: IMAP_Write() failed attempting to send LOGIN command to IMAP server: %s", Username, ClientAddr, sin_port, strerror( errno ) );
	    goto fail;
	}
	
	/*
	 * the server response should be a go ahead
	 */
	if ( ( rc = IMAP_Line_Read( &Server ) ) == -1 )
	{
	    syslog(LOG_INFO, "LOGIN: '******' (%s:%d) failed: Failed to receive go-ahead from IMAP server after sending LOGIN command", Username, ClientAddr, sin_port );
	    goto fail;
	}

	if ( Server.LiteralBytesRemaining )
	{
	    syslog(LOG_ERR, "%s: Unexpected string literal in server banner response.  Should be a continuation response.", fn );
	    goto fail;
	    
	}
	
	if ( Server.ReadBuf[0] != '+' )
	{
	    syslog( LOG_INFO, "LOGIN: '******' (%s:%d) failed: bad response from server after sending string literal specifier", Username, ClientAddr, sin_port );
	    goto fail;
	}
	
	/* 
	 * now send the password
	 */
	snprintf( SendBuf, BufLen, "%s\r\n", Password );
	
	if ( IMAP_Write( Server.conn, SendBuf, strlen( SendBuf ) ) == -1 )
	{
	    syslog(LOG_INFO, "LOGIN: '******' (%s:%d) failed: IMAP_Write() failed attempting to send literal password to IMAP server: %s", Username, ClientAddr, sin_port, strerror( errno ) );
	    goto fail;
	}
    }
    else
    {
	/*
	 * just send the login command via normal means.
	 */
	snprintf( SendBuf, BufLen, "A0001 LOGIN %s %s\r\n", 
		  Username, Password );
	
	if ( IMAP_Write( Server.conn, SendBuf, strlen(SendBuf) ) == -1 )
	{
	    syslog(LOG_INFO, "LOGIN: '******' (%s:%d) failed: IMAP_Write() failed attempting to send LOGIN command to IMAP server: %s", Username, ClientAddr, sin_port, strerror( errno ) );
	    goto fail;
	}
    }
    
	
    /*
     * Read the server response.  From RFC 3501:
     *
     * A server MAY include a CAPABILITY response code in the tagged OK
     * response to a successful LOGIN command in order to send
     * capabilities automatically.  It is unnecessary for a client to
     * send a separate CAPABILITY command if it recognizes these
     * automatic capabilities.
     *
     * We have to be ready for the possibility that this might be an 
     * untagged response...  In an ideal world, we'd want to pass the
     * untagged stuff back to the client.  For now, since the RFC doesn't
     * mandate that behaviour, we're not going to since we don't have a client
     * socket descriptor to send it to.
     */
    for ( ;; )
    {
	if ( ( rc = IMAP_Line_Read( &Server ) ) == -1 )
	{
	    syslog(LOG_INFO, "LOGIN: '******' (%s:%d) failed: No response from IMAP server after sending LOGIN command", Username, ClientAddr, sin_port );
	    goto fail;
	}

	if ( Server.LiteralBytesRemaining )
	{
	    syslog(LOG_ERR, "%s: Unexpected string literal in server LOGIN response.", fn );
	    goto fail;
	    
	}
	
	if ( Server.ReadBuf[0] != '*' )
	    break;
    }
    
    
    /*
     * Try to match up the tag in the server response to the client tag.
     */
    endptr = Server.ReadBuf + rc;
    
    tokenptr = memtok( Server.ReadBuf, endptr, &last );
    
    if ( !tokenptr )
    {
	/* 
	 * no tokens found in server response?  Not likely, but we still
	 * have to check.
	 */
	syslog(LOG_INFO, "LOGIN: '******' (%s:%d) failed: server response to LOGIN command contained no tokens.", Username, ClientAddr, sin_port );
	goto fail;
    }
    
    if ( memcmp( (const void *)tokenptr, (const void *)"A0001", 
		 strlen( tokenptr ) ) )
    {
	/* 
	 * non-matching tag read back from the server... Lord knows what this
	 * is, so we'll fail.
	 */
	syslog(LOG_INFO, "LOGIN: '******' (%s:%d) failed: server response to LOGIN command contained non-matching tag.", Username, ClientAddr, sin_port );
	goto fail;
    }
    
    
    /*
     * Now that we've matched the tags up, see if the response was 'OK'
     */
    tokenptr = memtok( NULL, endptr, &last );
    
    if ( !tokenptr )
    {
	/* again, not likely but we still have to check... */
	syslog(LOG_INFO, "LOGIN: '******' (%s:%d) failed: Malformed server response to LOGIN command", Username, ClientAddr, sin_port );
	goto fail;
    }
    
    if ( memcmp( (const void *)tokenptr, "OK", 2 ) )
    {
	/*
	 * If the server sent back a "NO" or "BAD", we can look at the actual
	 * server logs to figure out why.  We don't have to break our ass here
	 * putting the string back together just for the sake of logging.
	 */
	syslog(LOG_INFO, "LOGIN: '******' (%s:%d) failed: non-OK server response to LOGIN command", Username, ClientAddr, sin_port );
	goto fail;
    }
    
    /*
     * put this in our used list and remove it from the free list
     */
    for( ; ; )
    {
	LockMutex( &mp );
	
	if ( ICC_free->next )
	{
	    /* generate the hash index */
	    HashIndex = Hash( Username, HASH_TABLE_SIZE );
	    
	    /* temporarily store the address of the next free structure */
	    ICC_tptr = ICC_free->next;
	    
	    /*
	     * We want to add the newest "used" structure at the front of
	     * the list at the hash index.
	     */
	    ICC_free->next = ICC_HashTable[ HashIndex ];
	    ICC_HashTable[ HashIndex ] = ICC_free;
	    
	    /* 
	     * less typing and more readability, set an "active" pointer.
	     */
	    ICC_Active = ICC_free;
	    
	    /* now point the free listhead to the next available free struct */
	    ICC_free = ICC_tptr;
	    
	    /* fill in the newest used (oxymoron?) structure */
	    strncpy( ICC_Active->username, Username, 
		     sizeof ICC_Active->username );
	    ICC_Active->username[ sizeof ICC_Active->username - 1 ] = '\0';
	    memcpy( ICC_Active->hashedpw, md5pw, sizeof ICC_Active->hashedpw );
	    ICC_Active->logouttime = 0;    /* zero means, "it's active". */
	    ICC_Active->server_conn = Server.conn;
	    
	    UnLockMutex( &mp );
	    
	    IMAPCount->InUseServerConnections++;
	    IMAPCount->TotalServerConnectionsCreated++;

	    if ( IMAPCount->InUseServerConnections >
		 IMAPCount->PeakInUseServerConnections )
		IMAPCount->PeakInUseServerConnections = IMAPCount->InUseServerConnections;
	    syslog(LOG_INFO, "LOGIN: '******' (%s:%d) on new sd [%d]", Username, ClientAddr, sin_port, Server.conn->sd );
	    return( Server.conn );
	}
	
	/*
	 * There weren't any free ICC structs.  Try to free one.  Make sure
	 * we unlock the mutex, since ICC_Recycle needs to obtain it.
	 */
	UnLockMutex( &mp );
	
	Expiration = abs( Expiration / 2 );
	
	/*
	 * Eventually, we have to fail
	 */
	if ( Expiration <= 2 )
	{
	    syslog(LOG_INFO, "LOGIN: '******' (%s:%d) failed: Out of free ICC structs.", Username, ClientAddr, sin_port );
	    goto fail;
	}
	
	ICC_Recycle( Expiration );
	
    }
    
  fail:
#if HAVE_LIBSSL
    if ( Server.conn->tls )
    {
	SSL_shutdown( Server.conn->tls );
	SSL_free( Server.conn->tls );
    }
#endif
    close( Server.conn->sd );
    free( Server.conn );
    return( NULL );
}
示例#11
0
文件: d1_lib.c 项目: actank/openssl
int DTLSv1_listen(SSL *s, BIO_ADDR *client)
{
    int next, n, ret = 0, clearpkt = 0;
    unsigned char cookie[DTLS1_COOKIE_LENGTH];
    unsigned char seq[SEQ_NUM_SIZE];
    const unsigned char *data;
    unsigned char *p, *buf;
    unsigned long reclen, fragoff, fraglen, msglen;
    unsigned int rectype, versmajor, msgseq, msgtype, clientvers, cookielen;
    BIO *rbio, *wbio;
    BUF_MEM *bufm;
    BIO_ADDR *tmpclient = NULL;
    PACKET pkt, msgpkt, msgpayload, session, cookiepkt;

    /* Ensure there is no state left over from a previous invocation */
    if (!SSL_clear(s))
        return -1;

    ERR_clear_error();

    rbio = SSL_get_rbio(s);
    wbio = SSL_get_wbio(s);

    if(!rbio || !wbio) {
        SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_BIO_NOT_SET);
        return -1;
    }

    /*
     * We only peek at incoming ClientHello's until we're sure we are going to
     * to respond with a HelloVerifyRequest. If its a ClientHello with a valid
     * cookie then we leave it in the BIO for accept to handle.
     */
    BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 1, NULL);

    /*
     * Note: This check deliberately excludes DTLS1_BAD_VER because that version
     * requires the MAC to be calculated *including* the first ClientHello
     * (without the cookie). Since DTLSv1_listen is stateless that cannot be
     * supported. DTLS1_BAD_VER must use cookies in a stateful manner (e.g. via
     * SSL_accept)
     */
    if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00)) {
        SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_UNSUPPORTED_SSL_VERSION);
        return -1;
    }

    if (s->init_buf == NULL) {
        if ((bufm = BUF_MEM_new()) == NULL) {
            SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_MALLOC_FAILURE);
            return -1;
        }

        if (!BUF_MEM_grow(bufm, SSL3_RT_MAX_PLAIN_LENGTH)) {
            BUF_MEM_free(bufm);
            SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_MALLOC_FAILURE);
            return -1;
        }
        s->init_buf = bufm;
    }
    buf = (unsigned char *)s->init_buf->data;

    do {
        /* Get a packet */

        clear_sys_error();
        /*
         * Technically a ClientHello could be SSL3_RT_MAX_PLAIN_LENGTH
         * + DTLS1_RT_HEADER_LENGTH bytes long. Normally init_buf does not store
         * the record header as well, but we do here. We've set up init_buf to
         * be the standard size for simplicity. In practice we shouldn't ever
         * receive a ClientHello as long as this. If we do it will get dropped
         * in the record length check below.
         */
        n = BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH);

        if (n <= 0) {
            if(BIO_should_retry(rbio)) {
                /* Non-blocking IO */
                goto end;
            }
            return -1;
        }

        /* If we hit any problems we need to clear this packet from the BIO */
        clearpkt = 1;

        if (!PACKET_buf_init(&pkt, buf, n)) {
            SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_INTERNAL_ERROR);
            return -1;
        }

        /*
         * Parse the received record. If there are any problems with it we just
         * dump it - with no alert. RFC6347 says this "Unlike TLS, DTLS is
         * resilient in the face of invalid records (e.g., invalid formatting,
         * length, MAC, etc.).  In general, invalid records SHOULD be silently
         * discarded, thus preserving the association; however, an error MAY be
         * logged for diagnostic purposes."
         */

        /* this packet contained a partial record, dump it */
        if (n < DTLS1_RT_HEADER_LENGTH) {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_RECORD_TOO_SMALL);
            goto end;
        }

        if (s->msg_callback)
            s->msg_callback(0, 0, SSL3_RT_HEADER, buf,
                            DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);

        /* Get the record header */
        if (!PACKET_get_1(&pkt, &rectype)
            || !PACKET_get_1(&pkt, &versmajor)) {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH);
            goto end;
        }

        if (rectype != SSL3_RT_HANDSHAKE)  {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_UNEXPECTED_MESSAGE);
            goto end;
        }

        /*
         * Check record version number. We only check that the major version is
         * the same.
         */
        if (versmajor != DTLS1_VERSION_MAJOR) {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_BAD_PROTOCOL_VERSION_NUMBER);
            goto end;
        }

        if (!PACKET_forward(&pkt, 1)
            /* Save the sequence number: 64 bits, with top 2 bytes = epoch */
            || !PACKET_copy_bytes(&pkt, seq, SEQ_NUM_SIZE)
            || !PACKET_get_length_prefixed_2(&pkt, &msgpkt)) {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH);
            goto end;
        }
        /*
         * We allow data remaining at the end of the packet because there could
         * be a second record (but we ignore it)
         */

        /* This is an initial ClientHello so the epoch has to be 0 */
        if (seq[0] != 0 || seq[1] != 0) {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_UNEXPECTED_MESSAGE);
            goto end;
        }

        /* Get a pointer to the raw message for the later callback */
        data = PACKET_data(&msgpkt);

        /* Finished processing the record header, now process the message */
        if (!PACKET_get_1(&msgpkt, &msgtype)
            || !PACKET_get_net_3(&msgpkt, &msglen)
            || !PACKET_get_net_2(&msgpkt, &msgseq)
            || !PACKET_get_net_3(&msgpkt, &fragoff)
            || !PACKET_get_net_3(&msgpkt, &fraglen)
            || !PACKET_get_sub_packet(&msgpkt, &msgpayload, fraglen)
            || PACKET_remaining(&msgpkt) != 0) {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH);
            goto end;
        }

        if (msgtype != SSL3_MT_CLIENT_HELLO) {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_UNEXPECTED_MESSAGE);
            goto end;
        }

        /* Message sequence number can only be 0 or 1 */
        if(msgseq > 2) {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_INVALID_SEQUENCE_NUMBER);
            goto end;
        }

        /*
         * We don't support fragment reassembly for ClientHellos whilst
         * listening because that would require server side state (which is
         * against the whole point of the ClientHello/HelloVerifyRequest
         * mechanism). Instead we only look at the first ClientHello fragment
         * and require that the cookie must be contained within it.
         */
        if (fragoff != 0 || fraglen > msglen) {
            /* Non initial ClientHello fragment (or bad fragment) */
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_FRAGMENTED_CLIENT_HELLO);
            goto end;
        }

        if (s->msg_callback)
            s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, data,
                            fraglen + DTLS1_HM_HEADER_LENGTH, s,
                            s->msg_callback_arg);

        if (!PACKET_get_net_2(&msgpayload, &clientvers)) {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH);
            goto end;
        }

        /*
         * Verify client version is supported
         */
        if (DTLS_VERSION_LT(clientvers, (unsigned int)s->method->version) &&
            s->method->version != DTLS_ANY_VERSION) {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_WRONG_VERSION_NUMBER);
            goto end;
        }

        if (!PACKET_forward(&msgpayload, SSL3_RANDOM_SIZE)
            || !PACKET_get_length_prefixed_1(&msgpayload, &session)
            || !PACKET_get_length_prefixed_1(&msgpayload, &cookiepkt)) {
            /*
             * Could be malformed or the cookie does not fit within the initial
             * ClientHello fragment. Either way we can't handle it.
             */
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH);
            goto end;
        }

        /*
         * Check if we have a cookie or not. If not we need to send a
         * HelloVerifyRequest.
         */
        if (PACKET_remaining(&cookiepkt) == 0) {
            next = LISTEN_SEND_VERIFY_REQUEST;
        } else {
            /*
             * We have a cookie, so lets check it.
             */
            if (s->ctx->app_verify_cookie_cb == NULL) {
                SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_NO_VERIFY_COOKIE_CALLBACK);
                /* This is fatal */
                return -1;
            }
            if (s->ctx->app_verify_cookie_cb(s, PACKET_data(&cookiepkt),
                                             PACKET_remaining(&cookiepkt)) ==
                0) {
                /*
                 * We treat invalid cookies in the same was as no cookie as
                 * per RFC6347
                 */
                next = LISTEN_SEND_VERIFY_REQUEST;
            } else {
                /* Cookie verification succeeded */
                next = LISTEN_SUCCESS;
            }
        }

        if (next == LISTEN_SEND_VERIFY_REQUEST) {
            /*
             * There was no cookie in the ClientHello so we need to send a
             * HelloVerifyRequest. If this fails we do not worry about trying
             * to resend, we just drop it.
             */

            /*
             * Dump the read packet, we don't need it any more. Ignore return
             * value
             */
            BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 0, NULL);
            BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH);
            BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 1, NULL);

            /* Generate the cookie */
            if (s->ctx->app_gen_cookie_cb == NULL ||
                s->ctx->app_gen_cookie_cb(s, cookie, &cookielen) == 0 ||
                cookielen > 255) {
                SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_COOKIE_GEN_CALLBACK_FAILURE);
                /* This is fatal */
                return -1;
            }

            p = &buf[DTLS1_RT_HEADER_LENGTH];
            msglen = dtls_raw_hello_verify_request(p + DTLS1_HM_HEADER_LENGTH,
                                                   cookie, cookielen);

            *p++ = DTLS1_MT_HELLO_VERIFY_REQUEST;

            /* Message length */
            l2n3(msglen, p);

            /* Message sequence number is always 0 for a HelloVerifyRequest */
            s2n(0, p);

            /*
             * We never fragment a HelloVerifyRequest, so fragment offset is 0
             * and fragment length is message length
             */
            l2n3(0, p);
            l2n3(msglen, p);

            /* Set reclen equal to length of whole handshake message */
            reclen = msglen + DTLS1_HM_HEADER_LENGTH;

            /* Add the record header */
            p = buf;

            *(p++) = SSL3_RT_HANDSHAKE;
            /*
             * Special case: for hello verify request, client version 1.0 and we
             * haven't decided which version to use yet send back using version
             * 1.0 header: otherwise some clients will ignore it.
             */
            if (s->method->version == DTLS_ANY_VERSION) {
                *(p++) = DTLS1_VERSION >> 8;
                *(p++) = DTLS1_VERSION & 0xff;
            } else {
                *(p++) = s->version >> 8;
                *(p++) = s->version & 0xff;
            }

            /*
             * Record sequence number is always the same as in the received
             * ClientHello
             */
            memcpy(p, seq, SEQ_NUM_SIZE);
            p += SEQ_NUM_SIZE;

            /* Length */
            s2n(reclen, p);

            /*
             * Set reclen equal to length of whole record including record
             * header
             */
            reclen += DTLS1_RT_HEADER_LENGTH;

            if (s->msg_callback)
                s->msg_callback(1, 0, SSL3_RT_HEADER, buf,
                                DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);


            if ((tmpclient = BIO_ADDR_new()) == NULL) {
                SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_MALLOC_FAILURE);
                goto end;
            }

            /*
             * This is unneccessary if rbio and wbio are one and the same - but
             * maybe they're not. We ignore errors here - some BIOs do not
             * support this.
             */
            if(BIO_dgram_get_peer(rbio, tmpclient) > 0) {
                (void)BIO_dgram_set_peer(wbio, tmpclient);
            }
            BIO_ADDR_free(tmpclient);
            tmpclient = NULL;

            if (BIO_write(wbio, buf, reclen) < (int)reclen) {
                if(BIO_should_retry(wbio)) {
                    /*
                     * Non-blocking IO...but we're stateless, so we're just
                     * going to drop this packet.
                     */
                    goto end;
                }
                return -1;
            }

            if (BIO_flush(wbio) <= 0) {
                if(BIO_should_retry(wbio)) {
                    /*
                     * Non-blocking IO...but we're stateless, so we're just
                     * going to drop this packet.
                     */
                    goto end;
                }
                return -1;
            }
        }
示例#12
0
文件: d1_srvr.c 项目: bentju/packages
int dtls1_accept(SSL *s)
	{
	BUF_MEM *buf;
	unsigned long Time=(unsigned long)time(NULL);
	void (*cb)(const SSL *ssl,int type,int val)=NULL;
	unsigned long alg_k;
	int ret= -1;
	int new_state,state,skip=0;
	int listen;

	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;
	
	listen = s->d1->listen;

	/* init things to blank */
	s->in_handshake++;
	if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);

	s->d1->listen = listen;

	if (s->cert == NULL)
		{
		SSLerr(SSL_F_DTLS1_ACCEPT,SSL_R_NO_CERTIFICATE_SET);
		return(-1);
		}

	for (;;)
		{
		state=s->state;

		switch (s->state)
			{
		case SSL_ST_RENEGOTIATE:
			s->new_session=1;
			/* s->state=SSL_ST_ACCEPT; */

		case SSL_ST_BEFORE:
		case SSL_ST_ACCEPT:
		case SSL_ST_BEFORE|SSL_ST_ACCEPT:
		case SSL_ST_OK|SSL_ST_ACCEPT:

			s->server=1;
			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);

			if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00))
				{
				SSLerr(SSL_F_DTLS1_ACCEPT, ERR_R_INTERNAL_ERROR);
				return -1;
				}
			s->type=SSL_ST_ACCEPT;

			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;
				}

			if (!ssl3_setup_buffers(s))
				{
				ret= -1;
				goto end;
				}

			s->init_num=0;

			if (s->state != SSL_ST_RENEGOTIATE)
				{
				/* Ok, we now need to push on a buffering BIO so that
				 * the output is sent in a way that TCP likes :-)
				 */
				if (!ssl_init_wbio_buffer(s,1)) { ret= -1; goto end; }

				ssl3_init_finished_mac(s);
				s->state=SSL3_ST_SR_CLNT_HELLO_A;
				s->ctx->stats.sess_accept++;
				}
			else
				{
				/* s->state == SSL_ST_RENEGOTIATE,
				 * we will just send a HelloRequest */
				s->ctx->stats.sess_accept_renegotiate++;
				s->state=SSL3_ST_SW_HELLO_REQ_A;
				}

			break;

		case SSL3_ST_SW_HELLO_REQ_A:
		case SSL3_ST_SW_HELLO_REQ_B:

			s->shutdown=0;
			dtls1_start_timer(s);
			ret=dtls1_send_hello_request(s);
			if (ret <= 0) goto end;
			s->s3->tmp.next_state=SSL3_ST_SW_HELLO_REQ_C;
			s->state=SSL3_ST_SW_FLUSH;
			s->init_num=0;

			ssl3_init_finished_mac(s);
			break;

		case SSL3_ST_SW_HELLO_REQ_C:
			s->state=SSL_ST_OK;
			break;

		case SSL3_ST_SR_CLNT_HELLO_A:
		case SSL3_ST_SR_CLNT_HELLO_B:
		case SSL3_ST_SR_CLNT_HELLO_C:

			s->shutdown=0;
			ret=ssl3_get_client_hello(s);
			if (ret <= 0) goto end;
			dtls1_stop_timer(s);

			if (ret == 1 && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE))
				s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A;
			else
				s->state = SSL3_ST_SW_SRVR_HELLO_A;

			s->init_num=0;

			/* Reflect ClientHello sequence to remain stateless while listening */
			if (listen)
				{
				memcpy(s->s3->write_sequence, s->s3->read_sequence, sizeof(s->s3->write_sequence));
				}

			/* If we're just listening, stop here */
			if (listen && s->state == SSL3_ST_SW_SRVR_HELLO_A)
				{
				ret = 2;
				s->d1->listen = 0;
				/* Set expected sequence numbers
				 * to continue the handshake.
				 */
				s->d1->handshake_read_seq = 2;
				s->d1->handshake_write_seq = 1;
				s->d1->next_handshake_write_seq = 1;
				goto end;
				}
			
			break;
			
		case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A:
		case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B:

			ret = dtls1_send_hello_verify_request(s);
			if ( ret <= 0) goto end;
			s->state=SSL3_ST_SW_FLUSH;
			s->s3->tmp.next_state=SSL3_ST_SR_CLNT_HELLO_A;

			/* HelloVerifyRequest resets Finished MAC */
			if (s->version != DTLS1_BAD_VER)
				ssl3_init_finished_mac(s);
			break;
			
		case SSL3_ST_SW_SRVR_HELLO_A:
		case SSL3_ST_SW_SRVR_HELLO_B:
			s->new_session = 2;
			dtls1_start_timer(s);
			ret=dtls1_send_server_hello(s);
			if (ret <= 0) goto end;

#ifndef OPENSSL_NO_TLSEXT
			if (s->hit)
				{
				if (s->tlsext_ticket_expected)
					s->state=SSL3_ST_SW_SESSION_TICKET_A;
				else
					s->state=SSL3_ST_SW_CHANGE_A;
				}
#else
			if (s->hit)
					s->state=SSL3_ST_SW_CHANGE_A;
#endif
			else
				s->state=SSL3_ST_SW_CERT_A;
			s->init_num=0;
			break;

		case SSL3_ST_SW_CERT_A:
		case SSL3_ST_SW_CERT_B:
			/* Check if it is anon DH or normal PSK */
			if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
				&& !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
				{
				dtls1_start_timer(s);
				ret=dtls1_send_server_certificate(s);
				if (ret <= 0) goto end;
#ifndef OPENSSL_NO_TLSEXT
				if (s->tlsext_status_expected)
					s->state=SSL3_ST_SW_CERT_STATUS_A;
				else
					s->state=SSL3_ST_SW_KEY_EXCH_A;
				}
			else
				{
				skip = 1;
				s->state=SSL3_ST_SW_KEY_EXCH_A;
				}
#else
				}
			else
				skip=1;

			s->state=SSL3_ST_SW_KEY_EXCH_A;
#endif
			s->init_num=0;
			break;

		case SSL3_ST_SW_KEY_EXCH_A:
		case SSL3_ST_SW_KEY_EXCH_B:
			alg_k = s->s3->tmp.new_cipher->algorithm_mkey;

			/* clear this, it may get reset by
			 * send_server_key_exchange */
			if ((s->options & SSL_OP_EPHEMERAL_RSA)
#ifndef OPENSSL_NO_KRB5
				&& !(alg_k & SSL_kKRB5)
#endif /* OPENSSL_NO_KRB5 */
				)
				/* option SSL_OP_EPHEMERAL_RSA sends temporary RSA key
				 * even when forbidden by protocol specs
				 * (handshake may fail as clients are not required to
				 * be able to handle this) */
				s->s3->tmp.use_rsa_tmp=1;
			else
				s->s3->tmp.use_rsa_tmp=0;

			/* only send if a DH key exchange or
			 * RSA but we have a sign only certificate */
			if (s->s3->tmp.use_rsa_tmp
			/* PSK: send ServerKeyExchange if PSK identity
			 * hint if provided */
#ifndef OPENSSL_NO_PSK
			    || ((alg_k & SSL_kPSK) && s->ctx->psk_identity_hint)
#endif
			    || (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
			    || (alg_k & SSL_kEECDH)
			    || ((alg_k & SSL_kRSA)
				&& (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
				    || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)
					&& EVP_PKEY_size(s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)
					)
				    )
				)
			    )
				{
				dtls1_start_timer(s);
				ret=dtls1_send_server_key_exchange(s);
				if (ret <= 0) goto end;
				}
			else
				skip=1;

			s->state=SSL3_ST_SW_CERT_REQ_A;
			s->init_num=0;
			break;

		case SSL3_ST_SW_CERT_REQ_A:
		case SSL3_ST_SW_CERT_REQ_B:
			if (/* don't request cert unless asked for it: */
				!(s->verify_mode & SSL_VERIFY_PEER) ||
				/* if SSL_VERIFY_CLIENT_ONCE is set,
				 * don't request cert during re-negotiation: */
				((s->session->peer != NULL) &&
				 (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) ||
				/* never request cert in anonymous ciphersuites
				 * (see section "Certificate request" in SSL 3 drafts
				 * and in RFC 2246): */
				((s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
				 /* ... except when the application insists on verification
				  * (against the specs, but s3_clnt.c accepts this for SSL 3) */
				 !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) ||
				 /* never request cert in Kerberos ciphersuites */
				(s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5)
				/* With normal PSK Certificates and
				 * Certificate Requests are omitted */
				|| (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
				{
				/* no cert request */
				skip=1;
				s->s3->tmp.cert_request=0;
				s->state=SSL3_ST_SW_SRVR_DONE_A;
				}
			else
				{
				s->s3->tmp.cert_request=1;
				dtls1_start_timer(s);
				ret=dtls1_send_certificate_request(s);
				if (ret <= 0) goto end;
#ifndef NETSCAPE_HANG_BUG
				s->state=SSL3_ST_SW_SRVR_DONE_A;
#else
				s->state=SSL3_ST_SW_FLUSH;
				s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
#endif
				s->init_num=0;
				}
			break;

		case SSL3_ST_SW_SRVR_DONE_A:
		case SSL3_ST_SW_SRVR_DONE_B:
			dtls1_start_timer(s);
			ret=dtls1_send_server_done(s);
			if (ret <= 0) goto end;
			s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
			s->state=SSL3_ST_SW_FLUSH;
			s->init_num=0;
			break;
		
		case SSL3_ST_SW_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 SSL3_ST_SR_CERT_A:
		case SSL3_ST_SR_CERT_B:
			/* Check for second client hello (MS SGC) */
			ret = ssl3_check_client_hello(s);
			if (ret <= 0)
				goto end;
			if (ret == 2)
				{
				dtls1_stop_timer(s);
				s->state = SSL3_ST_SR_CLNT_HELLO_C;
				}
			else {
				/* could be sent for a DH cert, even if we
				 * have not asked for it :-) */
				ret=ssl3_get_client_certificate(s);
				if (ret <= 0) goto end;
				s->init_num=0;
				s->state=SSL3_ST_SR_KEY_EXCH_A;
			}
			break;

		case SSL3_ST_SR_KEY_EXCH_A:
		case SSL3_ST_SR_KEY_EXCH_B:
			ret=ssl3_get_client_key_exchange(s);
			if (ret <= 0) goto end;
			s->state=SSL3_ST_SR_CERT_VRFY_A;
			s->init_num=0;

			if (ret == 2)
				{
				/* For the ECDH ciphersuites when
				 * the client sends its ECDH pub key in
				 * a certificate, the CertificateVerify
				 * message is not sent.
				 */
				s->state=SSL3_ST_SR_FINISHED_A;
				s->init_num = 0;
				}
			else
				{
				s->state=SSL3_ST_SR_CERT_VRFY_A;
				s->init_num=0;

				/* We need to get hashes here so if there is
				 * a client cert, it can be verified */ 
				s->method->ssl3_enc->cert_verify_mac(s,
					NID_md5,
					&(s->s3->tmp.cert_verify_md[0]));
				s->method->ssl3_enc->cert_verify_mac(s,
					NID_sha1,
					&(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]));
				}
			break;

		case SSL3_ST_SR_CERT_VRFY_A:
		case SSL3_ST_SR_CERT_VRFY_B:

			s->d1->change_cipher_spec_ok = 1;
			/* we should decide if we expected this one */
			ret=ssl3_get_cert_verify(s);
			if (ret <= 0) goto end;

			s->state=SSL3_ST_SR_FINISHED_A;
			s->init_num=0;
			break;

		case SSL3_ST_SR_FINISHED_A:
		case SSL3_ST_SR_FINISHED_B:
			s->d1->change_cipher_spec_ok = 1;
			ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A,
				SSL3_ST_SR_FINISHED_B);
			if (ret <= 0) goto end;
			dtls1_stop_timer(s);
			if (s->hit)
				s->state=SSL_ST_OK;
#ifndef OPENSSL_NO_TLSEXT
			else if (s->tlsext_ticket_expected)
				s->state=SSL3_ST_SW_SESSION_TICKET_A;
#endif
			else
				s->state=SSL3_ST_SW_CHANGE_A;
			s->init_num=0;
			break;

#ifndef OPENSSL_NO_TLSEXT
		case SSL3_ST_SW_SESSION_TICKET_A:
		case SSL3_ST_SW_SESSION_TICKET_B:
			ret=dtls1_send_newsession_ticket(s);
			if (ret <= 0) goto end;
			s->state=SSL3_ST_SW_CHANGE_A;
			s->init_num=0;
			break;

		case SSL3_ST_SW_CERT_STATUS_A:
		case SSL3_ST_SW_CERT_STATUS_B:
			ret=ssl3_send_cert_status(s);
			if (ret <= 0) goto end;
			s->state=SSL3_ST_SW_KEY_EXCH_A;
			s->init_num=0;
			break;

#endif

		case SSL3_ST_SW_CHANGE_A:
		case SSL3_ST_SW_CHANGE_B:

			s->session->cipher=s->s3->tmp.new_cipher;
			if (!s->method->ssl3_enc->setup_key_block(s))
				{ ret= -1; goto end; }

			ret=dtls1_send_change_cipher_spec(s,
				SSL3_ST_SW_CHANGE_A,SSL3_ST_SW_CHANGE_B);

			if (ret <= 0) goto end;
			s->state=SSL3_ST_SW_FINISHED_A;
			s->init_num=0;

			if (!s->method->ssl3_enc->change_cipher_state(s,
				SSL3_CHANGE_CIPHER_SERVER_WRITE))
				{
				ret= -1;
				goto end;
				}

			dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
			break;

		case SSL3_ST_SW_FINISHED_A:
		case SSL3_ST_SW_FINISHED_B:
			ret=dtls1_send_finished(s,
				SSL3_ST_SW_FINISHED_A,SSL3_ST_SW_FINISHED_B,
				s->method->ssl3_enc->server_finished_label,
				s->method->ssl3_enc->server_finished_label_len);
			if (ret <= 0) goto end;
			s->state=SSL3_ST_SW_FLUSH;
			if (s->hit)
				s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
			else
				s->s3->tmp.next_state=SSL_ST_OK;
			s->init_num=0;
			break;

		case SSL_ST_OK:
			/* clean a few things up */
			ssl3_cleanup_key_block(s);

#if 0
			BUF_MEM_free(s->init_buf);
			s->init_buf=NULL;
#endif

			/* remove buffering on output */
			ssl_free_wbio_buffer(s);

			s->init_num=0;

			if (s->new_session == 2) /* skipped if we just sent a HelloRequest */
				{
				/* actually not necessarily a 'new' session unless
				 * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is set */
				
				s->new_session=0;
				
				ssl_update_cache(s,SSL_SESS_CACHE_SERVER);
				
				s->ctx->stats.sess_accept_good++;
				/* s->server=1; */
				s->handshake_func=dtls1_accept;

				if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1);
				}
			
			ret = 1;

			/* done handshaking, next message is client hello */
			s->d1->handshake_read_seq = 0;
			/* next message is server hello */
			s->d1->handshake_write_seq = 0;
			s->d1->next_handshake_write_seq = 0;
			goto end;
			/* break; */

		default:
			SSLerr(SSL_F_DTLS1_ACCEPT,SSL_R_UNKNOWN_STATE);
			ret= -1;
			goto end;
			/* break; */
			}
示例#13
0
int dtls1_accept(SSL *s)
  {
  BUF_MEM *buf;
  unsigned long l,Time=time(NULL);
  void (*cb)(const SSL *ssl,int type,int val)=NULL;
  long num1;
  int ret= -1;
  int new_state,state,skip=0;

  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;

  /* init things to blank */
  s->in_handshake++;
  if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);

  if (s->cert == NULL)
    {
    SSLerr(SSL_F_DTLS1_ACCEPT,SSL_R_NO_CERTIFICATE_SET);
    return(-1);
    }

  for (;;)
    {
    state=s->state;

    switch (s->state)
      {
    case SSL_ST_RENEGOTIATE:
      s->new_session=1;
      /* s->state=SSL_ST_ACCEPT; */

    case SSL_ST_BEFORE:
    case SSL_ST_ACCEPT:
    case SSL_ST_BEFORE|SSL_ST_ACCEPT:
    case SSL_ST_OK|SSL_ST_ACCEPT:

      s->server=1;
      if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);

      if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00))
        {
        SSLerr(SSL_F_DTLS1_ACCEPT, ERR_R_INTERNAL_ERROR);
        return -1;
        }
      s->type=SSL_ST_ACCEPT;

      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;
        }

      if (!ssl3_setup_buffers(s))
        {
        ret= -1;
        goto end;
        }

      s->init_num=0;

      if (s->state != SSL_ST_RENEGOTIATE)
        {
        /* Ok, we now need to push on a buffering BIO so that
         * the output is sent in a way that TCP likes :-)
         */
        if (!ssl_init_wbio_buffer(s,1)) { ret= -1; goto end; }

        ssl3_init_finished_mac(s);
        s->state=SSL3_ST_SR_CLNT_HELLO_A;
        s->ctx->stats.sess_accept++;
        }
      else
        {
        /* s->state == SSL_ST_RENEGOTIATE,
         * we will just send a HelloRequest */
        s->ctx->stats.sess_accept_renegotiate++;
        s->state=SSL3_ST_SW_HELLO_REQ_A;
        }

            if ( (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE))
                s->d1->send_cookie = 1;
            else
                s->d1->send_cookie = 0;

      break;

    case SSL3_ST_SW_HELLO_REQ_A:
    case SSL3_ST_SW_HELLO_REQ_B:

      s->shutdown=0;
      ret=dtls1_send_hello_request(s);
      if (ret <= 0) goto end;
      s->s3->tmp.next_state=SSL3_ST_SW_HELLO_REQ_C;
      s->state=SSL3_ST_SW_FLUSH;
      s->init_num=0;

      ssl3_init_finished_mac(s);
      break;

    case SSL3_ST_SW_HELLO_REQ_C:
      s->state=SSL_ST_OK;
      break;

    case SSL3_ST_SR_CLNT_HELLO_A:
    case SSL3_ST_SR_CLNT_HELLO_B:
    case SSL3_ST_SR_CLNT_HELLO_C:

      s->shutdown=0;
      ret=ssl3_get_client_hello(s);
      if (ret <= 0) goto end;
      s->new_session = 2;

      if ( s->d1->send_cookie)
        s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A;
      else
        s->state = SSL3_ST_SW_SRVR_HELLO_A;

      s->init_num=0;
      break;
      
    case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A:
    case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B:

      ret = dtls1_send_hello_verify_request(s);
      if ( ret <= 0) goto end;
      s->d1->send_cookie = 0;
      s->state=SSL3_ST_SW_FLUSH;
      s->s3->tmp.next_state=SSL3_ST_SR_CLNT_HELLO_A;
      break;
      
    case SSL3_ST_SW_SRVR_HELLO_A:
    case SSL3_ST_SW_SRVR_HELLO_B:
      ret=dtls1_send_server_hello(s);
      if (ret <= 0) goto end;

      if (s->hit)
        s->state=SSL3_ST_SW_CHANGE_A;
      else
        s->state=SSL3_ST_SW_CERT_A;
      s->init_num=0;
      break;

    case SSL3_ST_SW_CERT_A:
    case SSL3_ST_SW_CERT_B:
      /* Check if it is anon DH */
      if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL))
        {
        ret=dtls1_send_server_certificate(s);
        if (ret <= 0) goto end;
        }
      else
        skip=1;
      s->state=SSL3_ST_SW_KEY_EXCH_A;
      s->init_num=0;
      break;

    case SSL3_ST_SW_KEY_EXCH_A:
    case SSL3_ST_SW_KEY_EXCH_B:
      l=s->s3->tmp.new_cipher->algorithms;

      /* clear this, it may get reset by
       * send_server_key_exchange */
      if ((s->options & SSL_OP_EPHEMERAL_RSA)
#ifndef OPENSSL_NO_KRB5
        && !(l & SSL_KRB5)
#endif /* OPENSSL_NO_KRB5 */
        )
        /* option SSL_OP_EPHEMERAL_RSA sends temporary RSA key
         * even when forbidden by protocol specs
         * (handshake may fail as clients are not required to
         * be able to handle this) */
        s->s3->tmp.use_rsa_tmp=1;
      else
        s->s3->tmp.use_rsa_tmp=0;

      /* only send if a DH key exchange, fortezza or
       * RSA but we have a sign only certificate */
      if (s->s3->tmp.use_rsa_tmp
          || (l & (SSL_DH|SSL_kFZA))
          || ((l & SSL_kRSA)
        && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
            || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)
          && EVP_PKEY_size(s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)
          )
            )
        )
          )
        {
        ret=dtls1_send_server_key_exchange(s);
        if (ret <= 0) goto end;
        }
      else
        skip=1;

      s->state=SSL3_ST_SW_CERT_REQ_A;
      s->init_num=0;
      break;

    case SSL3_ST_SW_CERT_REQ_A:
    case SSL3_ST_SW_CERT_REQ_B:
      if (/* don't request cert unless asked for it: */
        !(s->verify_mode & SSL_VERIFY_PEER) ||
        /* if SSL_VERIFY_CLIENT_ONCE is set,
         * don't request cert during re-negotiation: */
        ((s->session->peer != NULL) &&
         (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) ||
        /* never request cert in anonymous ciphersuites
         * (see section "Certificate request" in SSL 3 drafts
         * and in RFC 2246): */
        ((s->s3->tmp.new_cipher->algorithms & SSL_aNULL) &&
         /* ... except when the application insists on verification
          * (against the specs, but s3_clnt.c accepts this for SSL 3) */
         !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) ||
                                 /* never request cert in Kerberos ciphersuites */
                                (s->s3->tmp.new_cipher->algorithms & SSL_aKRB5))
        {
        /* no cert request */
        skip=1;
        s->s3->tmp.cert_request=0;
        s->state=SSL3_ST_SW_SRVR_DONE_A;
        }
      else
        {
        s->s3->tmp.cert_request=1;
        ret=dtls1_send_certificate_request(s);
        if (ret <= 0) goto end;
#ifndef NETSCAPE_HANG_BUG
        s->state=SSL3_ST_SW_SRVR_DONE_A;
#else
        s->state=SSL3_ST_SW_FLUSH;
        s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
#endif
        s->init_num=0;
        }
      break;

    case SSL3_ST_SW_SRVR_DONE_A:
    case SSL3_ST_SW_SRVR_DONE_B:
      ret=dtls1_send_server_done(s);
      if (ret <= 0) goto end;
      s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
      s->state=SSL3_ST_SW_FLUSH;
      s->init_num=0;
      break;
    
    case SSL3_ST_SW_FLUSH:
      /* number of bytes to be flushed */
      num1=BIO_ctrl(s->wbio,BIO_CTRL_INFO,0,NULL);
      if (num1 > 0)
        {
        s->rwstate=SSL_WRITING;
        num1=BIO_flush(s->wbio);
        if (num1 <= 0) { ret= -1; goto end; }
        s->rwstate=SSL_NOTHING;
        }

      s->state=s->s3->tmp.next_state;
      break;

    case SSL3_ST_SR_CERT_A:
    case SSL3_ST_SR_CERT_B:
      /* Check for second client hello (MS SGC) */
      ret = ssl3_check_client_hello(s);
      if (ret <= 0)
        goto end;
      if (ret == 2)
        s->state = SSL3_ST_SR_CLNT_HELLO_C;
      else {
        /* could be sent for a DH cert, even if we
         * have not asked for it :-) */
        ret=ssl3_get_client_certificate(s);
        if (ret <= 0) goto end;
        s->init_num=0;
        s->state=SSL3_ST_SR_KEY_EXCH_A;
      }
      break;

    case SSL3_ST_SR_KEY_EXCH_A:
    case SSL3_ST_SR_KEY_EXCH_B:
      ret=ssl3_get_client_key_exchange(s);
      if (ret <= 0) goto end;
      s->state=SSL3_ST_SR_CERT_VRFY_A;
      s->init_num=0;

      /* We need to get hashes here so if there is
       * a client cert, it can be verified */ 
      s->method->ssl3_enc->cert_verify_mac(s,
        &(s->s3->finish_dgst1),
        &(s->s3->tmp.cert_verify_md[0]));
      s->method->ssl3_enc->cert_verify_mac(s,
        &(s->s3->finish_dgst2),
        &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]));

      break;

    case SSL3_ST_SR_CERT_VRFY_A:
    case SSL3_ST_SR_CERT_VRFY_B:

      /* we should decide if we expected this one */
      ret=ssl3_get_cert_verify(s);
      if (ret <= 0) goto end;

      s->state=SSL3_ST_SR_FINISHED_A;
      s->init_num=0;
      break;

    case SSL3_ST_SR_FINISHED_A:
    case SSL3_ST_SR_FINISHED_B:
      ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A,
        SSL3_ST_SR_FINISHED_B);
      if (ret <= 0) goto end;
      if (s->hit)
        s->state=SSL_ST_OK;
      else
        s->state=SSL3_ST_SW_CHANGE_A;
      s->init_num=0;
      break;

    case SSL3_ST_SW_CHANGE_A:
    case SSL3_ST_SW_CHANGE_B:

      s->session->cipher=s->s3->tmp.new_cipher;
      if (!s->method->ssl3_enc->setup_key_block(s))
        { ret= -1; goto end; }

      ret=dtls1_send_change_cipher_spec(s,
        SSL3_ST_SW_CHANGE_A,SSL3_ST_SW_CHANGE_B);

      if (ret <= 0) goto end;
      s->state=SSL3_ST_SW_FINISHED_A;
      s->init_num=0;

      if (!s->method->ssl3_enc->change_cipher_state(s,
        SSL3_CHANGE_CIPHER_SERVER_WRITE))
        {
        ret= -1;
        goto end;
        }

      dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
      break;

    case SSL3_ST_SW_FINISHED_A:
    case SSL3_ST_SW_FINISHED_B:
      ret=dtls1_send_finished(s,
        SSL3_ST_SW_FINISHED_A,SSL3_ST_SW_FINISHED_B,
        s->method->ssl3_enc->server_finished_label,
        s->method->ssl3_enc->server_finished_label_len);
      if (ret <= 0) goto end;
      s->state=SSL3_ST_SW_FLUSH;
      if (s->hit)
        s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
      else
        s->s3->tmp.next_state=SSL_ST_OK;
      s->init_num=0;
      break;

    case SSL_ST_OK:
      /* clean a few things up */
      ssl3_cleanup_key_block(s);

#if 0
      BUF_MEM_free(s->init_buf);
      s->init_buf=NULL;
#endif

      /* remove buffering on output */
      ssl_free_wbio_buffer(s);

      s->init_num=0;

      if (s->new_session == 2) /* skipped if we just sent a HelloRequest */
        {
        /* actually not necessarily a 'new' session unless
         * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is set */
        
        s->new_session=0;
        
        ssl_update_cache(s,SSL_SESS_CACHE_SERVER);
        
        s->ctx->stats.sess_accept_good++;
        /* s->server=1; */
        s->handshake_func=dtls1_accept;

        if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1);
        }
      
      ret = 1;

      /* done handshaking, next message is client hello */
      s->d1->handshake_read_seq = 0;
      /* next message is server hello */
      s->d1->handshake_write_seq = 0;
      goto end;
      /* break; */

    default:
      SSLerr(SSL_F_DTLS1_ACCEPT,SSL_R_UNKNOWN_STATE);
      ret= -1;
      goto end;
      /* break; */
      }
    
    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_ACCEPT_LOOP,1);
        s->state=new_state;
        }
      }
    skip=0;
    }
end:
  /* BIO_flush(s->wbio); */

  s->in_handshake--;
  if (cb != NULL)
    cb(s,SSL_CB_ACCEPT_EXIT,ret);
  return(ret);
  }
示例#14
0
/* handle_connect_results assumes that select or poll have already shown the
 * descriptor to be active */
void handle_connect_result(struct npool *ms, struct nevent *nse, enum nse_status status) {
  int optval;
  socklen_t optlen = sizeof(int);
  struct niod *iod = nse->iod;
#if HAVE_OPENSSL
  int sslerr;
  int rc = 0;
  int sslconnect_inprogress = nse->type == NSE_TYPE_CONNECT_SSL && nse->iod &&
    (nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ ||
     nse->sslinfo.ssl_desire == SSL_ERROR_WANT_WRITE);
#else
  int sslconnect_inprogress = 0;
#endif

  if (status == NSE_STATUS_TIMEOUT || status == NSE_STATUS_CANCELLED) {
    nse->status = status;
    nse->event_done = 1;
  } else if (sslconnect_inprogress) {
    /* Do nothing */
  } else if (status == NSE_STATUS_SUCCESS) {
    /* First we want to determine whether the socket really is connected */
    if (getsockopt(iod->sd, SOL_SOCKET, SO_ERROR, (char *)&optval, &optlen) != 0)
      optval = socket_errno(); /* Stupid Solaris */

    switch (optval) {
      case 0:
        nse->status = NSE_STATUS_SUCCESS;
        break;
      /* EACCES can be caused by ICMPv6 dest-unreach-admin, or when a port is
         blocked by Windows Firewall (WSAEACCES). */
      case EACCES:
      case ECONNREFUSED:
      case EHOSTUNREACH:
      case ENETDOWN:
      case ENETUNREACH:
      case ENETRESET:
      case ECONNABORTED:
      case ETIMEDOUT:
      case EHOSTDOWN:
      case ECONNRESET:
#ifdef WIN32
      case WSAEADDRINUSE:
      case WSAEADDRNOTAVAIL:
#endif
#ifndef WIN32
      case EPIPE: /* Has been seen after connect on Linux. */
      case ENOPROTOOPT: /* Also seen on Linux, perhaps in response to protocol unreachable. */
#endif
        nse->status = NSE_STATUS_ERROR;
        nse->errnum = optval;
        break;

      default:
        /* I'd like for someone to report it */
        fatal("Strange connect error from %s (%d): %s",
              inet_ntop_ez(&iod->peer, iod->peerlen), optval,
              socket_strerror(optval));
    }

    /* Now special code for the SSL case where the TCP connection was successful. */
    if (nse->type == NSE_TYPE_CONNECT_SSL &&
        nse->status == NSE_STATUS_SUCCESS) {
#if HAVE_OPENSSL
      assert(ms->sslctx != NULL);
      /* Reuse iod->ssl if present. If set, this is the second try at connection
         without the SSL_OP_NO_SSLv2 option set. */
      if (iod->ssl == NULL) {
        iod->ssl = SSL_new(ms->sslctx);
        if (!iod->ssl)
          fatal("SSL_new failed: %s", ERR_error_string(ERR_get_error(), NULL));
      }

#if HAVE_SSL_SET_TLSEXT_HOST_NAME
      if (iod->hostname != NULL) {
        if (SSL_set_tlsext_host_name(iod->ssl, iod->hostname) != 1)
          fatal("SSL_set_tlsext_host_name failed: %s", ERR_error_string(ERR_get_error(), NULL));
      }
#endif

      /* Associate our new SSL with the connected socket.  It will inherit the
       * non-blocking nature of the sd */
      if (SSL_set_fd(iod->ssl, iod->sd) != 1)
        fatal("SSL_set_fd failed: %s", ERR_error_string(ERR_get_error(), NULL));

      /* Event not done -- need to do SSL connect below */
      nse->sslinfo.ssl_desire = SSL_ERROR_WANT_CONNECT;
#endif
    } else {
      /* This is not an SSL connect (in which case we are always done), or the
       * TCP connect() underlying the SSL failed (in which case we are also done */
      nse->event_done = 1;
    }
  } else {
    fatal("Unknown status (%d)", status);
  }

  /* At this point the TCP connection is done, whether successful or not.
   * Therefore decrease the read/write listen counts that were incremented in
   * nsp_add_event. In the SSL case, we may increase one of the counts depending
   * on whether SSL_connect returns an error of SSL_ERROR_WANT_READ or
   * SSL_ERROR_WANT_WRITE. In that case we will re-enter this function, but we
   * don't want to execute this block again. */
  if (iod->sd != -1 && !sslconnect_inprogress) {
    int ev = EV_NONE;

    ev |= socket_count_read_dec(iod);
    ev |= socket_count_write_dec(iod);
    ev |= EV_EXCEPT;
    update_events(iod, ms, EV_NONE, ev);
  }

#if HAVE_OPENSSL
  if (nse->type == NSE_TYPE_CONNECT_SSL && !nse->event_done) {
    /* Lets now start/continue/finish the connect! */
    if (iod->ssl_session) {
      rc = SSL_set_session(iod->ssl, iod->ssl_session);
      if (rc == 0)
        nsock_log_error(ms, "Uh-oh: SSL_set_session() failed - please tell [email protected]");
      iod->ssl_session = NULL; /* No need for this any more */
    }

    /* If this is a reinvocation of handle_connect_result, clear out the listen
     * bits that caused it, based on the previous SSL desire. */
    if (sslconnect_inprogress) {
      int ev;

      ev = socket_count_dec_ssl_desire(nse);
      update_events(iod, ms, EV_NONE, ev);
    }

    rc = SSL_connect(iod->ssl);
    if (rc == 1) {
      /* Woop!  Connect is done! */
      nse->event_done = 1;
      /* Check that certificate verification was okay, if requested. */
      if (nsi_ssl_post_connect_verify(iod)) {
        nse->status = NSE_STATUS_SUCCESS;
      } else {
        nsock_log_error(ms, "certificate verification error for EID %li: %s",
                        nse->id, ERR_error_string(ERR_get_error(), NULL));
        nse->status = NSE_STATUS_ERROR;
      }
    } else {
      long options = SSL_get_options(iod->ssl);

      sslerr = SSL_get_error(iod->ssl, rc);
      if (rc == -1 && sslerr == SSL_ERROR_WANT_READ) {
        nse->sslinfo.ssl_desire = sslerr;
        socket_count_read_inc(iod);
        update_events(iod, ms, EV_READ, EV_NONE);
      } else if (rc == -1 && sslerr == SSL_ERROR_WANT_WRITE) {
        nse->sslinfo.ssl_desire = sslerr;
        socket_count_write_inc(iod);
        update_events(iod, ms, EV_WRITE, EV_NONE);
      } else if (!(options & SSL_OP_NO_SSLv2)) {
        int saved_ev;

        /* SSLv3-only and TLSv1-only servers can't be connected to when the
         * SSL_OP_NO_SSLv2 option is not set, which is the case when the pool
         * was initialized with nsp_ssl_init_max_speed. Try reconnecting with
         * SSL_OP_NO_SSLv2. Never downgrade a NO_SSLv2 connection to one that
         * might use SSLv2. */
        nsock_log_info(ms, "EID %li reconnecting with SSL_OP_NO_SSLv2", nse->id);

        saved_ev = iod->watched_events;
        nsock_engine_iod_unregister(ms, iod);
        close(iod->sd);
        nsock_connect_internal(ms, nse, SOCK_STREAM, iod->lastproto, &iod->peer,
                               iod->peerlen, nsi_peerport(iod));
        nsock_engine_iod_register(ms, iod, saved_ev);

        SSL_clear(iod->ssl);
        if(!SSL_clear(iod->ssl))
           fatal("SSL_clear failed: %s", ERR_error_string(ERR_get_error(), NULL));

        SSL_set_options(iod->ssl, options | SSL_OP_NO_SSLv2);
        socket_count_read_inc(nse->iod);
        socket_count_write_inc(nse->iod);
        update_events(iod, ms, EV_READ|EV_WRITE, EV_NONE);
        nse->sslinfo.ssl_desire = SSL_ERROR_WANT_CONNECT;
      } else {
        nsock_log_info(ms, "EID %li %s",
                       nse->id, ERR_error_string(ERR_get_error(), NULL));
        nse->event_done = 1;
        nse->status = NSE_STATUS_ERROR;
        nse->errnum = EIO;
      }
    }
  }
#endif
}
示例#15
0
文件: viossl.c 项目: Aitaobao/mysql
static int ssl_do(struct st_VioSSLFd *ptr, Vio *vio, long timeout,
                  int (*connect_accept_func)(SSL*), unsigned long *errptr)
{
  int r;
  SSL *ssl;
  my_bool unused;
  my_bool was_blocking;

  DBUG_ENTER("ssl_do");
  DBUG_PRINT("enter", ("ptr: 0x%lx, sd: %d  ctx: 0x%lx",
                       (long) ptr, vio->sd, (long) ptr->ssl_context));

  /* Set socket to blocking if not already set */
  vio_blocking(vio, 1, &was_blocking);

  if (!(ssl= SSL_new(ptr->ssl_context)))
  {
    DBUG_PRINT("error", ("SSL_new failure"));
    *errptr= ERR_get_error();
    vio_blocking(vio, was_blocking, &unused);
    DBUG_RETURN(1);
  }
  DBUG_PRINT("info", ("ssl: 0x%lx timeout: %ld", (long) ssl, timeout));
  SSL_clear(ssl);
  SSL_SESSION_set_timeout(SSL_get_session(ssl), timeout);
  SSL_set_fd(ssl, vio->sd);
#ifndef HAVE_YASSL
  /* Twitter MySQL build with system openssl (MySQL bug #68999) */
#ifdef SSL_OP_NO_COMPRESSION
  SSL_set_options(ssl, SSL_OP_NO_COMPRESSION);
#endif
#endif

  if ((r= connect_accept_func(ssl)) < 1)
  {
    DBUG_PRINT("error", ("SSL_connect/accept failure"));
    *errptr= SSL_get_error(ssl, r);
    SSL_free(ssl);
    vio_blocking(vio, was_blocking, &unused);
    DBUG_RETURN(1);
  }

  /*
    Connection succeeded. Install new function handlers,
    change type, set sd to the fd used when connecting
    and set pointer to the SSL structure
  */
  vio_reset(vio, VIO_TYPE_SSL, SSL_get_fd(ssl), 0, 0);
  vio->ssl_arg= (void*)ssl;

#ifndef DBUG_OFF
  {
    /* Print some info about the peer */
    X509 *cert;
    char buf[512];

    DBUG_PRINT("info",("SSL connection succeeded"));
    DBUG_PRINT("info",("Using cipher: '%s'" , SSL_get_cipher_name(ssl)));

    if ((cert= SSL_get_peer_certificate (ssl)))
    {
      DBUG_PRINT("info",("Peer certificate:"));
      X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
      DBUG_PRINT("info",("\t subject: '%s'", buf));
      X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf));
      DBUG_PRINT("info",("\t issuer: '%s'", buf));
      X509_free(cert);
    }
    else
      DBUG_PRINT("info",("Peer does not have certificate."));

    if (SSL_get_shared_ciphers(ssl, buf, sizeof(buf)))
    {
      DBUG_PRINT("info",("shared_ciphers: '%s'", buf));
    }
    else
      DBUG_PRINT("info",("no shared ciphers!"));
  }
#endif

  DBUG_RETURN(0);
}
示例#16
0
文件: s23_clnt.c 项目: aburgh/openbsd
int
ssl23_connect(SSL *s)
{
	void (*cb)(const SSL *ssl, int type, int val) = NULL;
	int ret = -1;
	int new_state, state;

	ERR_clear_error();
	errno = 0;

	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);

	for (;;) {
		state = s->state;

		switch (s->state) {
		case SSL_ST_BEFORE:
		case SSL_ST_CONNECT:
		case SSL_ST_BEFORE|SSL_ST_CONNECT:
		case SSL_ST_OK|SSL_ST_CONNECT:

			if (s->session != NULL) {
				SSLerr(SSL_F_SSL23_CONNECT, SSL_R_SSL23_DOING_SESSION_ID_REUSE);
				ret = -1;
				goto end;
			}
			s->server = 0;
			if (cb != NULL)
				cb(s, SSL_CB_HANDSHAKE_START, 1);

			/* s->version=TLS1_VERSION; */
			s->type = SSL_ST_CONNECT;

			if (!ssl3_setup_init_buffer(s)) {
				ret = -1;
				goto end;
			}
			if (!ssl3_setup_buffers(s)) {
				ret = -1;
				goto end;
			}
			if (!ssl3_init_finished_mac(s)) {
				ret = -1;
				goto end;
			}

			s->state = SSL23_ST_CW_CLNT_HELLO_A;
			s->ctx->stats.sess_connect++;
			s->init_num = 0;
			break;

		case SSL23_ST_CW_CLNT_HELLO_A:
		case SSL23_ST_CW_CLNT_HELLO_B:

			s->shutdown = 0;
			ret = ssl23_client_hello(s);
			if (ret <= 0)
				goto end;
			s->state = SSL23_ST_CR_SRVR_HELLO_A;
			s->init_num = 0;

			break;

		case SSL23_ST_CR_SRVR_HELLO_A:
		case SSL23_ST_CR_SRVR_HELLO_B:
			ret = ssl23_get_server_hello(s);
			if (ret >= 0)
				cb = NULL;
			goto end;
			/* break; */

		default:
			SSLerr(SSL_F_SSL23_CONNECT, SSL_R_UNKNOWN_STATE);
			ret = -1;
			goto end;
			/* break; */
		}

		if (s->debug) {
			(void)BIO_flush(s->wbio);
		}

		if ((cb != NULL) && (s->state != state)) {
			new_state = s->state;
			s->state = state;
			cb(s, SSL_CB_CONNECT_LOOP, 1);
			s->state = new_state;
		}
	}

end:
	s->in_handshake--;
	if (cb != NULL)
		cb(s, SSL_CB_CONNECT_EXIT, ret);

	return (ret);
}
示例#17
0
int dtls1_accept(SSL *s)
{
    BUF_MEM *buf;
    unsigned long Time = (unsigned long)time(NULL);
    void (*cb) (const SSL *ssl, int type, int val) = NULL;
    unsigned long alg_k;
    int ret = -1;
    int new_state, state, skip = 0;
#ifndef OPENSSL_NO_SCTP
    unsigned char sctpauthkey[64];
    char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
#endif

    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;

    /* init things to blank */
    s->in_handshake++;
    if (!SSL_in_init(s) || SSL_in_before(s)) {
        if (!SSL_clear(s))
            return -1;
    }

#ifndef OPENSSL_NO_SCTP
    /*
     * Notify SCTP BIO socket to enter handshake mode and prevent stream
     * identifier other than 0. Will be ignored if no SCTP is used.
     */
    BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE,
             s->in_handshake, NULL);
#endif

#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) {
        dtls1_stop_timer(s);
        s->tlsext_hb_pending = 0;
        s->tlsext_hb_seq++;
    }
#endif

    for (;;) {
        state = s->state;

        switch (s->state) {
        case SSL_ST_RENEGOTIATE:
            s->renegotiate = 1;
            /* s->state=SSL_ST_ACCEPT; */

        case SSL_ST_BEFORE:
        case SSL_ST_ACCEPT:
        case SSL_ST_BEFORE | SSL_ST_ACCEPT:
        case SSL_ST_OK | SSL_ST_ACCEPT:

            s->server = 1;
            if (cb != NULL)
                cb(s, SSL_CB_HANDSHAKE_START, 1);

            if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00)) {
                SSLerr(SSL_F_DTLS1_ACCEPT, ERR_R_INTERNAL_ERROR);
                return -1;
            }
            s->type = SSL_ST_ACCEPT;

            if (s->init_buf == NULL) {
                if ((buf = BUF_MEM_new()) == NULL) {
                    ret = -1;
                    s->state = SSL_ST_ERR;
                    goto end;
                }
                if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
                    BUF_MEM_free(buf);
                    ret = -1;
                    s->state = SSL_ST_ERR;
                    goto end;
                }
                s->init_buf = buf;
            }

            if (!ssl3_setup_buffers(s)) {
                ret = -1;
                s->state = SSL_ST_ERR;
                goto end;
            }

            s->init_num = 0;
            /*
             * Should have been reset by ssl3_get_finished, too.
             */
            s->s3->change_cipher_spec = 0;

            if (s->state != SSL_ST_RENEGOTIATE) {
                /*
                 * Ok, we now need to push on a buffering BIO so that the
                 * output is sent in a way that TCP likes :-) ...but not with
                 * SCTP :-)
                 */
#ifndef OPENSSL_NO_SCTP
                if (!BIO_dgram_is_sctp(SSL_get_wbio(s)))
#endif
                    if (!ssl_init_wbio_buffer(s, 1)) {
                        ret = -1;
                        s->state = SSL_ST_ERR;
                        goto end;
                    }

                ssl3_init_finished_mac(s);
                s->state = SSL3_ST_SR_CLNT_HELLO_A;
                s->ctx->stats.sess_accept++;
            } else {
                /*
                 * s->state == SSL_ST_RENEGOTIATE, we will just send a
                 * HelloRequest
                 */
                s->ctx->stats.sess_accept_renegotiate++;
                s->state = SSL3_ST_SW_HELLO_REQ_A;
            }

            break;

        case SSL3_ST_SW_HELLO_REQ_A:
        case SSL3_ST_SW_HELLO_REQ_B:

            s->shutdown = 0;
            dtls1_clear_record_buffer(s);
            dtls1_start_timer(s);
            ret = ssl3_send_hello_request(s);
            if (ret <= 0)
                goto end;
            s->s3->tmp.next_state = SSL3_ST_SR_CLNT_HELLO_A;
            s->state = SSL3_ST_SW_FLUSH;
            s->init_num = 0;

            ssl3_init_finished_mac(s);
            break;

        case SSL3_ST_SW_HELLO_REQ_C:
            s->state = SSL_ST_OK;
            break;

        case SSL3_ST_SR_CLNT_HELLO_A:
        case SSL3_ST_SR_CLNT_HELLO_B:
        case SSL3_ST_SR_CLNT_HELLO_C:

            s->shutdown = 0;
            ret = ssl3_get_client_hello(s);
            if (ret <= 0)
                goto end;
            dtls1_stop_timer(s);

            if (ret == 1 && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE))
                s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A;
            else
                s->state = SSL3_ST_SW_SRVR_HELLO_A;

            s->init_num = 0;
            break;

        case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A:
        case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B:

            ret = dtls1_send_hello_verify_request(s);
            if (ret <= 0)
                goto end;
            s->state = SSL3_ST_SW_FLUSH;
            s->s3->tmp.next_state = SSL3_ST_SR_CLNT_HELLO_A;

            /* HelloVerifyRequest resets Finished MAC */
            if (s->version != DTLS1_BAD_VER)
                ssl3_init_finished_mac(s);
            break;

#ifndef OPENSSL_NO_SCTP
        case DTLS1_SCTP_ST_SR_READ_SOCK:

            if (BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
                s->s3->in_read_app_data = 2;
                s->rwstate = SSL_READING;
                BIO_clear_retry_flags(SSL_get_rbio(s));
                BIO_set_retry_read(SSL_get_rbio(s));
                ret = -1;
                goto end;
            }

            s->state = SSL3_ST_SR_CHANGE_A;
            break;

        case DTLS1_SCTP_ST_SW_WRITE_SOCK:
            ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s));
            if (ret < 0)
                goto end;

            if (ret == 0) {
                if (s->d1->next_state != SSL_ST_OK) {
                    s->s3->in_read_app_data = 2;
                    s->rwstate = SSL_READING;
                    BIO_clear_retry_flags(SSL_get_rbio(s));
                    BIO_set_retry_read(SSL_get_rbio(s));
                    ret = -1;
                    goto end;
                }
            }

            s->state = s->d1->next_state;
            break;
#endif

        case SSL3_ST_SW_SRVR_HELLO_A:
        case SSL3_ST_SW_SRVR_HELLO_B:
            s->renegotiate = 2;
            dtls1_start_timer(s);
            ret = ssl3_send_server_hello(s);
            if (ret <= 0)
                goto end;

            if (s->hit) {
#ifndef OPENSSL_NO_SCTP
                /*
                 * Add new shared key for SCTP-Auth, will be ignored if no
                 * SCTP used.
                 */
                snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
                         DTLS1_SCTP_AUTH_LABEL);

                if (SSL_export_keying_material(s, sctpauthkey,
                        sizeof(sctpauthkey), labelbuffer,
                        sizeof(labelbuffer), NULL, 0, 0) <= 0) {
                    ret = -1;
                    s->state = SSL_ST_ERR;
                    goto end;
                }

                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
                         sizeof(sctpauthkey), sctpauthkey);
#endif
                if (s->tlsext_ticket_expected)
                    s->state = SSL3_ST_SW_SESSION_TICKET_A;
                else
                    s->state = SSL3_ST_SW_CHANGE_A;
            } else
                s->state = SSL3_ST_SW_CERT_A;
            s->init_num = 0;
            break;

        case SSL3_ST_SW_CERT_A:
        case SSL3_ST_SW_CERT_B:
            /* Check if it is anon DH or normal PSK */
            if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
                && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) {
                dtls1_start_timer(s);
                ret = ssl3_send_server_certificate(s);
                if (ret <= 0)
                    goto end;

                if (s->tlsext_status_expected)
                    s->state = SSL3_ST_SW_CERT_STATUS_A;
                else
                    s->state = SSL3_ST_SW_KEY_EXCH_A;
            } else {
                skip = 1;
                s->state = SSL3_ST_SW_KEY_EXCH_A;
            }
            s->init_num = 0;
            break;

        case SSL3_ST_SW_KEY_EXCH_A:
        case SSL3_ST_SW_KEY_EXCH_B:
            alg_k = s->s3->tmp.new_cipher->algorithm_mkey;

            /*
             * clear this, it may get reset by
             * send_server_key_exchange
             */
            s->s3->tmp.use_rsa_tmp = 0;

            /*
             * only send if a DH key exchange or RSA but we have a sign only
             * certificate
             */
            if (0
                /*
                 * PSK: send ServerKeyExchange if PSK identity hint if
                 * provided
                 */
#ifndef OPENSSL_NO_PSK
                || ((alg_k & SSL_kPSK) && s->cert->psk_identity_hint)
#endif
                || (alg_k & SSL_kDHE)
                || (alg_k & SSL_kECDHE)
                || ((alg_k & SSL_kRSA)
                    && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
                        || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)
                            && EVP_PKEY_size(s->cert->pkeys
                                             [SSL_PKEY_RSA_ENC].privatekey) *
                            8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)
                        )
                    )
                )
                ) {
                dtls1_start_timer(s);
                ret = ssl3_send_server_key_exchange(s);
                if (ret <= 0)
                    goto end;
            } else
                skip = 1;

            s->state = SSL3_ST_SW_CERT_REQ_A;
            s->init_num = 0;
            break;

        case SSL3_ST_SW_CERT_REQ_A:
        case SSL3_ST_SW_CERT_REQ_B:
            if (                /* don't request cert unless asked for it: */
                   !(s->verify_mode & SSL_VERIFY_PEER) ||
                   /*
                    * if SSL_VERIFY_CLIENT_ONCE is set, don't request cert
                    * during re-negotiation:
                    */
                   ((s->session->peer != NULL) &&
                    (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) ||
                   /*
                    * never request cert in anonymous ciphersuites (see
                    * section "Certificate request" in SSL 3 drafts and in
                    * RFC 2246):
                    */
                   ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
                   /*
                    * ... except when the application insists on
                    * verification (against the specs, but s3_clnt.c accepts
                    * this for SSL 3)
                    */
                   !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
                   /*
                    * With normal PSK Certificates and Certificate Requests
                    * are omitted
                    */
                   || (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) {
                /* no cert request */
                skip = 1;
                s->s3->tmp.cert_request = 0;
                s->state = SSL3_ST_SW_SRVR_DONE_A;
#ifndef OPENSSL_NO_SCTP
                if (BIO_dgram_is_sctp(SSL_get_wbio(s))) {
                    s->d1->next_state = SSL3_ST_SW_SRVR_DONE_A;
                    s->state = DTLS1_SCTP_ST_SW_WRITE_SOCK;
                }
#endif
            } else {
                s->s3->tmp.cert_request = 1;
                dtls1_start_timer(s);
                ret = ssl3_send_certificate_request(s);
                if (ret <= 0)
                    goto end;
                s->state = SSL3_ST_SW_SRVR_DONE_A;
# ifndef OPENSSL_NO_SCTP
                if (BIO_dgram_is_sctp(SSL_get_wbio(s))) {
                    s->d1->next_state = SSL3_ST_SW_SRVR_DONE_A;
                    s->state = DTLS1_SCTP_ST_SW_WRITE_SOCK;
                }
# endif
                s->init_num = 0;
            }
            break;

        case SSL3_ST_SW_SRVR_DONE_A:
        case SSL3_ST_SW_SRVR_DONE_B:
            dtls1_start_timer(s);
            ret = ssl3_send_server_done(s);
            if (ret <= 0)
                goto end;
            s->s3->tmp.next_state = SSL3_ST_SR_CERT_A;
            s->state = SSL3_ST_SW_FLUSH;
            s->init_num = 0;
            break;

        case SSL3_ST_SW_FLUSH:
            s->rwstate = SSL_WRITING;
            if (BIO_flush(s->wbio) <= 0) {
                /*
                 * If the write error was fatal, stop trying
                 */
                if (!BIO_should_retry(s->wbio)) {
                    s->rwstate = SSL_NOTHING;
                    s->state = s->s3->tmp.next_state;
                }

                ret = -1;
                goto end;
            }
            s->rwstate = SSL_NOTHING;
            s->state = s->s3->tmp.next_state;
            break;

        case SSL3_ST_SR_CERT_A:
        case SSL3_ST_SR_CERT_B:
            if (s->s3->tmp.cert_request) {
                ret = ssl3_get_client_certificate(s);
                if (ret <= 0)
                    goto end;
            }
            s->init_num = 0;
            s->state = SSL3_ST_SR_KEY_EXCH_A;
            break;

        case SSL3_ST_SR_KEY_EXCH_A:
        case SSL3_ST_SR_KEY_EXCH_B:
            ret = ssl3_get_client_key_exchange(s);
            if (ret <= 0)
                goto end;
#ifndef OPENSSL_NO_SCTP
            /*
             * Add new shared key for SCTP-Auth, will be ignored if no SCTP
             * used.
             */
            snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
                     DTLS1_SCTP_AUTH_LABEL);

            if (SSL_export_keying_material(s, sctpauthkey,
                                       sizeof(sctpauthkey), labelbuffer,
                                       sizeof(labelbuffer), NULL, 0, 0) <= 0) {
                ret = -1;
                s->state = SSL_ST_ERR;
                goto end;
            }

            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
                     sizeof(sctpauthkey), sctpauthkey);
#endif

            s->state = SSL3_ST_SR_CERT_VRFY_A;
            s->init_num = 0;

            if (ret == 2) {
                /*
                 * For the ECDH ciphersuites when the client sends its ECDH
                 * pub key in a certificate, the CertificateVerify message is
                 * not sent.
                 */
                s->state = SSL3_ST_SR_CHANGE_A;
                s->init_num = 0;
            } else if (SSL_USE_SIGALGS(s)) {
                s->state = SSL3_ST_SR_CERT_VRFY_A;
                s->init_num = 0;
                if (!s->session->peer)
                    break;
                if (!s->s3->handshake_buffer) {
                    SSLerr(SSL_F_DTLS1_ACCEPT, ERR_R_INTERNAL_ERROR);
                    s->state = SSL_ST_ERR;
                    return -1;
                }
                /*
                 * For sigalgs freeze the handshake buffer. If we support
                 * extms we've done this already.
                 */
                if (!ssl3_digest_cached_records(s, 1)) {
                    s->state = SSL_ST_ERR;
                    return -1;
                }
            } else {
                s->state = SSL3_ST_SR_CERT_VRFY_A;
                s->init_num = 0;

                /*
                 * We need to get hashes here so if there is a client cert,
                 * it can be verified
                 */
                s->method->ssl3_enc->cert_verify_mac(s,
                                                     NID_md5,
                                                     &(s->s3->
                                                       tmp.cert_verify_md
                                                       [0]));
                s->method->ssl3_enc->cert_verify_mac(s, NID_sha1,
                                                     &(s->s3->
                                                       tmp.cert_verify_md
                                                       [MD5_DIGEST_LENGTH]));
            }
            break;

        case SSL3_ST_SR_CERT_VRFY_A:
        case SSL3_ST_SR_CERT_VRFY_B:
            ret = ssl3_get_cert_verify(s);
            if (ret <= 0)
                goto end;
#ifndef OPENSSL_NO_SCTP
            if (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
                state == SSL_ST_RENEGOTIATE)
                s->state = DTLS1_SCTP_ST_SR_READ_SOCK;
            else
#endif
                s->state = SSL3_ST_SR_CHANGE_A;
            s->init_num = 0;
            break;

        case SSL3_ST_SR_CHANGE_A:
        case SSL3_ST_SR_CHANGE_B:
            ret = ssl3_get_change_cipher_spec(s, SSL3_ST_SR_CHANGE_A,
                                              SSL3_ST_SR_CHANGE_B);
            if (ret <= 0)
                goto end;

            s->state = SSL3_ST_SR_FINISHED_A;
            s->init_num = 0;
            break;

        case SSL3_ST_SR_FINISHED_A:
        case SSL3_ST_SR_FINISHED_B:
            ret = ssl3_get_finished(s, SSL3_ST_SR_FINISHED_A,
                                    SSL3_ST_SR_FINISHED_B);
            if (ret <= 0)
                goto end;
            dtls1_stop_timer(s);
            if (s->hit)
                s->state = SSL_ST_OK;
            else if (s->tlsext_ticket_expected)
                s->state = SSL3_ST_SW_SESSION_TICKET_A;
            else
                s->state = SSL3_ST_SW_CHANGE_A;
            s->init_num = 0;
            break;

        case SSL3_ST_SW_SESSION_TICKET_A:
        case SSL3_ST_SW_SESSION_TICKET_B:
            ret = ssl3_send_newsession_ticket(s);
            if (ret <= 0)
                goto end;
            s->state = SSL3_ST_SW_CHANGE_A;
            s->init_num = 0;
            break;

        case SSL3_ST_SW_CERT_STATUS_A:
        case SSL3_ST_SW_CERT_STATUS_B:
            ret = ssl3_send_cert_status(s);
            if (ret <= 0)
                goto end;
            s->state = SSL3_ST_SW_KEY_EXCH_A;
            s->init_num = 0;
            break;

        case SSL3_ST_SW_CHANGE_A:
        case SSL3_ST_SW_CHANGE_B:

            s->session->cipher = s->s3->tmp.new_cipher;
            if (!s->method->ssl3_enc->setup_key_block(s)) {
                ret = -1;
                s->state = SSL_ST_ERR;
                goto end;
            }

            ret = dtls1_send_change_cipher_spec(s,
                                                SSL3_ST_SW_CHANGE_A,
                                                SSL3_ST_SW_CHANGE_B);

            if (ret <= 0)
                goto end;

#ifndef OPENSSL_NO_SCTP
            if (!s->hit) {
                /*
                 * Change to new shared key of SCTP-Auth, will be ignored if
                 * no SCTP used.
                 */
                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
                         0, NULL);
            }
#endif

            s->state = SSL3_ST_SW_FINISHED_A;
            s->init_num = 0;

            if (!s->method->ssl3_enc->change_cipher_state(s,
                                                          SSL3_CHANGE_CIPHER_SERVER_WRITE))
            {
                ret = -1;
                s->state = SSL_ST_ERR;
                goto end;
            }

            dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
            break;

        case SSL3_ST_SW_FINISHED_A:
        case SSL3_ST_SW_FINISHED_B:
            ret = ssl3_send_finished(s,
                                     SSL3_ST_SW_FINISHED_A,
                                     SSL3_ST_SW_FINISHED_B,
                                     s->method->
                                     ssl3_enc->server_finished_label,
                                     s->method->
                                     ssl3_enc->server_finished_label_len);
            if (ret <= 0)
                goto end;
            s->state = SSL3_ST_SW_FLUSH;
            if (s->hit) {
                s->s3->tmp.next_state = SSL3_ST_SR_CHANGE_A;

#ifndef OPENSSL_NO_SCTP
                /*
                 * Change to new shared key of SCTP-Auth, will be ignored if
                 * no SCTP used.
                 */
                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
                         0, NULL);
#endif
            } else {
                s->s3->tmp.next_state = SSL_ST_OK;
#ifndef OPENSSL_NO_SCTP
                if (BIO_dgram_is_sctp(SSL_get_wbio(s))) {
                    s->d1->next_state = s->s3->tmp.next_state;
                    s->s3->tmp.next_state = DTLS1_SCTP_ST_SW_WRITE_SOCK;
                }
#endif
            }
            s->init_num = 0;
            break;

        case SSL_ST_OK:
            /* clean a few things up */
            ssl3_cleanup_key_block(s);

            /* remove buffering on output */
            ssl_free_wbio_buffer(s);

            s->init_num = 0;

            if (s->renegotiate == 2) { /* skipped if we just sent a
                                        * HelloRequest */
                s->renegotiate = 0;
                s->new_session = 0;

                ssl_update_cache(s, SSL_SESS_CACHE_SERVER);

                s->ctx->stats.sess_accept_good++;
                /* s->server=1; */
                s->handshake_func = dtls1_accept;

                if (cb != NULL)
                    cb(s, SSL_CB_HANDSHAKE_DONE, 1);
            }

            ret = 1;

            /* done handshaking, next message is client hello */
            s->d1->handshake_read_seq = 0;
            /* next message is server hello */
            s->d1->handshake_write_seq = 0;
            s->d1->next_handshake_write_seq = 0;
            goto end;
            /* break; */

        case SSL_ST_ERR:
        default:
            SSLerr(SSL_F_DTLS1_ACCEPT, SSL_R_UNKNOWN_STATE);
            ret = -1;
            goto end;
            /* break; */
        }

        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_ACCEPT_LOOP, 1);
                s->state = new_state;
            }
        }
        skip = 0;
    }
 end:
    /* BIO_flush(s->wbio); */

    s->in_handshake--;
#ifndef OPENSSL_NO_SCTP
    /*
     * Notify SCTP BIO socket to leave handshake mode and prevent stream
     * identifier other than 0. Will be ignored if no SCTP is used.
     */
    BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE,
             s->in_handshake, NULL);
#endif

    if (cb != NULL)
        cb(s, SSL_CB_ACCEPT_EXIT, ret);
    return (ret);
}
示例#18
0
int	SslSocket::clear()
{
	return SSL_clear(this->_ssl);
}
示例#19
0
int dtls1_connect(SSL *s)
	{
	BUF_MEM *buf=NULL;
	unsigned long Time=(unsigned long)TINYCLR_SSL_TIME(NULL);
	void (*cb)(const SSL *ssl,int type,int val)=NULL;
	int ret= -1;
	int new_state,state,skip=0;;

	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); 

	for (;;)
		{
		state=s->state;

		switch(s->state)
			{
		case SSL_ST_RENEGOTIATE:
			s->new_session=1;
			s->state=SSL_ST_CONNECT;
			s->ctx->stats.sess_connect_renegotiate++;
			/* break */
		case SSL_ST_BEFORE:
		case SSL_ST_CONNECT:
		case SSL_ST_BEFORE|SSL_ST_CONNECT:
		case SSL_ST_OK|SSL_ST_CONNECT:

			s->server=0;
			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);

			if ((s->version & 0xff00 ) != (DTLS1_VERSION & 0xff00) &&
			    (s->version & 0xff00 ) != (DTLS1_BAD_VER & 0xff00))
				{
				SSLerr(SSL_F_DTLS1_CONNECT, ERR_R_INTERNAL_ERROR);
				ret = -1;
				goto end;
				}
				
			/* s->version=SSL3_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; }

			/* don't push the buffering BIO quite yet */

			s->state=SSL3_ST_CW_CLNT_HELLO_A;
			s->ctx->stats.sess_connect++;
			s->init_num=0;
			/* mark client_random uninitialized */
			TINYCLR_SSL_MEMSET(s->s3->client_random,0,sizeof(s->s3->client_random));
			s->d1->send_cookie = 0;
			s->hit = 0;
			break;

		case SSL3_ST_CW_CLNT_HELLO_A:
		case SSL3_ST_CW_CLNT_HELLO_B:

			s->shutdown=0;

			/* every DTLS ClientHello resets Finished MAC */
			ssl3_init_finished_mac(s);

			dtls1_start_timer(s);
			ret=dtls1_client_hello(s);
			if (ret <= 0) goto end;

			if ( s->d1->send_cookie)
				{
				s->state=SSL3_ST_CW_FLUSH;
				s->s3->tmp.next_state=SSL3_ST_CR_SRVR_HELLO_A;
				}
			else
				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);
			if (ret <= 0) goto end;
			else
				{
				dtls1_stop_timer(s);
				if (s->hit)
					s->state=SSL3_ST_CR_FINISHED_A;
				else
					s->state=DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A;
				}
			s->init_num=0;
			break;

		case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A:
		case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B:

			ret = dtls1_get_hello_verify(s);
			if ( ret <= 0)
				goto end;
			dtls1_stop_timer(s);
			if ( s->d1->send_cookie) /* start again, with a cookie */
				s->state=SSL3_ST_CW_CLNT_HELLO_A;
			else
				s->state = SSL3_ST_CR_CERT_A;
			s->init_num = 0;
			break;

		case SSL3_ST_CR_CERT_A:
		case SSL3_ST_CR_CERT_B:
#ifndef OPENSSL_NO_TLSEXT
			ret=ssl3_check_finished(s);
			if (ret <= 0) goto end;
			if (ret == 2)
				{
				s->hit = 1;
				if (s->tlsext_ticket_expected)
					s->state=SSL3_ST_CR_SESSION_TICKET_A;
				else
					s->state=SSL3_ST_CR_FINISHED_A;
				s->init_num=0;
				break;
				}
#endif
			/* Check if it is anon DH or PSK */
			if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
			    !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
				{
				ret=ssl3_get_server_certificate(s);
				if (ret <= 0) goto end;
#ifndef OPENSSL_NO_TLSEXT
				if (s->tlsext_status_expected)
					s->state=SSL3_ST_CR_CERT_STATUS_A;
				else
					s->state=SSL3_ST_CR_KEY_EXCH_A;
				}
			else
				{
				skip = 1;
				s->state=SSL3_ST_CR_KEY_EXCH_A;
				}
#else
				}
			else
				skip=1;

			s->state=SSL3_ST_CR_KEY_EXCH_A;
#endif
			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);
			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);
			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);
			if (ret <= 0) goto end;
			if (s->s3->tmp.cert_req)
				s->state=SSL3_ST_CW_CERT_A;
			else
				s->state=SSL3_ST_CW_KEY_EXCH_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:
			dtls1_start_timer(s);
			ret=dtls1_send_client_certificate(s);
			if (ret <= 0) goto end;
			s->state=SSL3_ST_CW_KEY_EXCH_A;
			s->init_num=0;
			break;

		case SSL3_ST_CW_KEY_EXCH_A:
		case SSL3_ST_CW_KEY_EXCH_B:
			dtls1_start_timer(s);
			ret=dtls1_send_client_key_exchange(s);
			if (ret <= 0) goto end;
			/* EAY EAY EAY need to check for DH fix cert
			 * sent back */
			/* For TLS, cert_req is set to 2, so a cert chain
			 * of nothing is sent, but no verify packet is sent */
			if (s->s3->tmp.cert_req == 1)
				{
				s->state=SSL3_ST_CW_CERT_VRFY_A;
				}
			else
				{
				s->state=SSL3_ST_CW_CHANGE_A;
				s->s3->change_cipher_spec=0;
				}

			s->init_num=0;
			break;

		case SSL3_ST_CW_CERT_VRFY_A:
		case SSL3_ST_CW_CERT_VRFY_B:
			dtls1_start_timer(s);
			ret=dtls1_send_client_verify(s);
			if (ret <= 0) goto end;
			s->state=SSL3_ST_CW_CHANGE_A;
			s->init_num=0;
			s->s3->change_cipher_spec=0;
			break;

		case SSL3_ST_CW_CHANGE_A:
		case SSL3_ST_CW_CHANGE_B:
			dtls1_start_timer(s);
			ret=dtls1_send_change_cipher_spec(s,
				SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B);
			if (ret <= 0) goto end;
			s->state=SSL3_ST_CW_FINISHED_A;
			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;
				}
			
			dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
			break;

		case SSL3_ST_CW_FINISHED_A:
		case SSL3_ST_CW_FINISHED_B:
			dtls1_start_timer(s);
			ret=dtls1_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->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
				{
#ifndef OPENSSL_NO_TLSEXT
				/* Allow NewSessionTicket if ticket expected */
				if (s->tlsext_ticket_expected)
					s->s3->tmp.next_state=SSL3_ST_CR_SESSION_TICKET_A;
				else
#endif
				
				s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A;
				}
			s->init_num=0;
			break;

#ifndef OPENSSL_NO_TLSEXT
		case SSL3_ST_CR_SESSION_TICKET_A:
		case SSL3_ST_CR_SESSION_TICKET_B:
			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:
			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:
			s->d1->change_cipher_spec_ok = 1;
			ret=ssl3_get_finished(s,SSL3_ST_CR_FINISHED_A,
				SSL3_ST_CR_FINISHED_B);
			if (ret <= 0) goto end;
			dtls1_stop_timer(s);

			if (s->hit)
				s->state=SSL3_ST_CW_CHANGE_A;
			else
				s->state=SSL_ST_OK;
			s->init_num=0;
			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:
			/* clean a few things up */
			ssl3_cleanup_key_block(s);

#if 0
			if (s->init_buf != NULL)
				{
				BUF_MEM_free(s->init_buf);
				s->init_buf=NULL;
				}
#endif

			/* 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->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=dtls1_connect;
			s->ctx->stats.sess_connect_good++;

			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1);

			/* done with handshaking */
			s->d1->handshake_read_seq  = 0;
			s->d1->next_handshake_write_seq = 0;
			goto end;
			/* break; */
			
		default:
			SSLerr(SSL_F_DTLS1_CONNECT,SSL_R_UNKNOWN_STATE);
			ret= -1;
			goto end;
			/* break; */
			}
示例#20
0
int
dtls1_connect(SSL *s)
{
	void (*cb)(const SSL *ssl, int type, int val) = NULL;
	int ret = -1;
	int new_state, state, skip = 0;

	ERR_clear_error();
	errno = 0;

	if (s->internal->info_callback != NULL)
		cb = s->internal->info_callback;
	else if (s->ctx->internal->info_callback != NULL)
		cb = s->ctx->internal->info_callback;

	s->internal->in_handshake++;
	if (!SSL_in_init(s) || SSL_in_before(s))
		SSL_clear(s);


	for (;;) {
		state = S3I(s)->hs.state;

		switch (S3I(s)->hs.state) {
		case SSL_ST_RENEGOTIATE:
			s->internal->renegotiate = 1;
			S3I(s)->hs.state = SSL_ST_CONNECT;
			s->ctx->internal->stats.sess_connect_renegotiate++;
			/* break */
		case SSL_ST_BEFORE:
		case SSL_ST_CONNECT:
		case SSL_ST_BEFORE|SSL_ST_CONNECT:
		case SSL_ST_OK|SSL_ST_CONNECT:

			s->server = 0;
			if (cb != NULL)
				cb(s, SSL_CB_HANDSHAKE_START, 1);

			if ((s->version & 0xff00 ) != (DTLS1_VERSION & 0xff00)) {
				SSLerror(s, ERR_R_INTERNAL_ERROR);
				ret = -1;
				goto end;
			}

			/* s->version=SSL3_VERSION; */
			s->internal->type = SSL_ST_CONNECT;

			if (!ssl3_setup_init_buffer(s)) {
				ret = -1;
				goto end;
			}
			if (!ssl3_setup_buffers(s)) {
				ret = -1;
				goto end;
			}
			if (!ssl_init_wbio_buffer(s, 0)) {
				ret = -1;
				goto end;
			}

			/* don't push the buffering BIO quite yet */

			S3I(s)->hs.state = SSL3_ST_CW_CLNT_HELLO_A;
			s->ctx->internal->stats.sess_connect++;
			s->internal->init_num = 0;
			/* mark client_random uninitialized */
			memset(s->s3->client_random, 0,
			    sizeof(s->s3->client_random));
			D1I(s)->send_cookie = 0;
			s->internal->hit = 0;
			break;


		case SSL3_ST_CW_CLNT_HELLO_A:
		case SSL3_ST_CW_CLNT_HELLO_B:

			s->internal->shutdown = 0;

			/* every DTLS ClientHello resets Finished MAC */
			if (!tls1_init_finished_mac(s)) {
				ret = -1;
				goto end;
			}

			dtls1_start_timer(s);
			ret = ssl3_client_hello(s);
			if (ret <= 0)
				goto end;

			if (D1I(s)->send_cookie) {
				S3I(s)->hs.state = SSL3_ST_CW_FLUSH;
				S3I(s)->hs.next_state = SSL3_ST_CR_SRVR_HELLO_A;
			} else
				S3I(s)->hs.state = SSL3_ST_CR_SRVR_HELLO_A;

			s->internal->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);
			if (ret <= 0)
				goto end;
			else {
				if (s->internal->hit) {

					S3I(s)->hs.state = SSL3_ST_CR_FINISHED_A;
				} else
					S3I(s)->hs.state = DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A;
			}
			s->internal->init_num = 0;
			break;

		case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A:
		case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B:

			ret = dtls1_get_hello_verify(s);
			if (ret <= 0)
				goto end;
			dtls1_stop_timer(s);
			if ( D1I(s)->send_cookie) /* start again, with a cookie */
				S3I(s)->hs.state = SSL3_ST_CW_CLNT_HELLO_A;
			else
				S3I(s)->hs.state = SSL3_ST_CR_CERT_A;
			s->internal->init_num = 0;
			break;

		case SSL3_ST_CR_CERT_A:
		case SSL3_ST_CR_CERT_B:
			ret = ssl3_check_finished(s);
			if (ret <= 0)
				goto end;
			if (ret == 2) {
				s->internal->hit = 1;
				if (s->internal->tlsext_ticket_expected)
					S3I(s)->hs.state = SSL3_ST_CR_SESSION_TICKET_A;
				else
					S3I(s)->hs.state = SSL3_ST_CR_FINISHED_A;
				s->internal->init_num = 0;
				break;
			}
			/* Check if it is anon DH. */
			if (!(S3I(s)->hs.new_cipher->algorithm_auth &
			    SSL_aNULL)) {
				ret = ssl3_get_server_certificate(s);
				if (ret <= 0)
					goto end;
				if (s->internal->tlsext_status_expected)
					S3I(s)->hs.state = SSL3_ST_CR_CERT_STATUS_A;
				else
					S3I(s)->hs.state = SSL3_ST_CR_KEY_EXCH_A;
			} else {
				skip = 1;
				S3I(s)->hs.state = SSL3_ST_CR_KEY_EXCH_A;
			}
			s->internal->init_num = 0;
			break;

		case SSL3_ST_CR_KEY_EXCH_A:
		case SSL3_ST_CR_KEY_EXCH_B:
			ret = ssl3_get_server_key_exchange(s);
			if (ret <= 0)
				goto end;
			S3I(s)->hs.state = SSL3_ST_CR_CERT_REQ_A;
			s->internal->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);
			if (ret <= 0)
				goto end;
			S3I(s)->hs.state = SSL3_ST_CR_SRVR_DONE_A;
			s->internal->init_num = 0;
			break;

		case SSL3_ST_CR_SRVR_DONE_A:
		case SSL3_ST_CR_SRVR_DONE_B:
			ret = ssl3_get_server_done(s);
			if (ret <= 0)
				goto end;
			dtls1_stop_timer(s);
			if (S3I(s)->tmp.cert_req)
				S3I(s)->hs.next_state = SSL3_ST_CW_CERT_A;
			else
				S3I(s)->hs.next_state = SSL3_ST_CW_KEY_EXCH_A;
			s->internal->init_num = 0;
			S3I(s)->hs.state = S3I(s)->hs.next_state;
			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:
			dtls1_start_timer(s);
			ret = ssl3_send_client_certificate(s);
			if (ret <= 0)
				goto end;
			S3I(s)->hs.state = SSL3_ST_CW_KEY_EXCH_A;
			s->internal->init_num = 0;
			break;

		case SSL3_ST_CW_KEY_EXCH_A:
		case SSL3_ST_CW_KEY_EXCH_B:
			dtls1_start_timer(s);
			ret = ssl3_send_client_key_exchange(s);
			if (ret <= 0)
				goto end;

			/* EAY EAY EAY need to check for DH fix cert
			 * sent back */
			/* For TLS, cert_req is set to 2, so a cert chain
			 * of nothing is sent, but no verify packet is sent */
			if (S3I(s)->tmp.cert_req == 1) {
				S3I(s)->hs.state = SSL3_ST_CW_CERT_VRFY_A;
			} else {
				S3I(s)->hs.state = SSL3_ST_CW_CHANGE_A;
				S3I(s)->change_cipher_spec = 0;
			}

			s->internal->init_num = 0;
			break;

		case SSL3_ST_CW_CERT_VRFY_A:
		case SSL3_ST_CW_CERT_VRFY_B:
			dtls1_start_timer(s);
			ret = ssl3_send_client_verify(s);
			if (ret <= 0)
				goto end;
			S3I(s)->hs.state = SSL3_ST_CW_CHANGE_A;
			s->internal->init_num = 0;
			S3I(s)->change_cipher_spec = 0;
			break;

		case SSL3_ST_CW_CHANGE_A:
		case SSL3_ST_CW_CHANGE_B:
			if (!s->internal->hit)
				dtls1_start_timer(s);
			ret = dtls1_send_change_cipher_spec(s,
			    SSL3_ST_CW_CHANGE_A, SSL3_ST_CW_CHANGE_B);
			if (ret <= 0)
				goto end;

			S3I(s)->hs.state = SSL3_ST_CW_FINISHED_A;
			s->internal->init_num = 0;

			s->session->cipher = S3I(s)->hs.new_cipher;
			if (!tls1_setup_key_block(s)) {
				ret = -1;
				goto end;
			}

			if (!tls1_change_cipher_state(s,
			    SSL3_CHANGE_CIPHER_CLIENT_WRITE)) {
				ret = -1;
				goto end;
			}


			dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
			break;

		case SSL3_ST_CW_FINISHED_A:
		case SSL3_ST_CW_FINISHED_B:
			if (!s->internal->hit)
				dtls1_start_timer(s);
			ret = ssl3_send_finished(s,
			    SSL3_ST_CW_FINISHED_A, SSL3_ST_CW_FINISHED_B,
			    TLS_MD_CLIENT_FINISH_CONST,
			    TLS_MD_CLIENT_FINISH_CONST_SIZE);
			if (ret <= 0)
				goto end;
			S3I(s)->hs.state = SSL3_ST_CW_FLUSH;

			/* clear flags */
			s->s3->flags&= ~SSL3_FLAGS_POP_BUFFER;
			if (s->internal->hit) {
				S3I(s)->hs.next_state = SSL_ST_OK;
				if (s->s3->flags & SSL3_FLAGS_DELAY_CLIENT_FINISHED) {
					S3I(s)->hs.state = SSL_ST_OK;
					s->s3->flags |= SSL3_FLAGS_POP_BUFFER;
					S3I(s)->delay_buf_pop_ret = 0;
				}
			} else {

				/* Allow NewSessionTicket if ticket expected */
				if (s->internal->tlsext_ticket_expected)
					S3I(s)->hs.next_state =
					    SSL3_ST_CR_SESSION_TICKET_A;
				else
					S3I(s)->hs.next_state =
					    SSL3_ST_CR_FINISHED_A;
			}
			s->internal->init_num = 0;
			break;

		case SSL3_ST_CR_SESSION_TICKET_A:
		case SSL3_ST_CR_SESSION_TICKET_B:
			ret = ssl3_get_new_session_ticket(s);
			if (ret <= 0)
				goto end;
			S3I(s)->hs.state = SSL3_ST_CR_FINISHED_A;
			s->internal->init_num = 0;
			break;

		case SSL3_ST_CR_CERT_STATUS_A:
		case SSL3_ST_CR_CERT_STATUS_B:
			ret = ssl3_get_cert_status(s);
			if (ret <= 0)
				goto end;
			S3I(s)->hs.state = SSL3_ST_CR_KEY_EXCH_A;
			s->internal->init_num = 0;
			break;

		case SSL3_ST_CR_FINISHED_A:
		case SSL3_ST_CR_FINISHED_B:
			D1I(s)->change_cipher_spec_ok = 1;
			ret = ssl3_get_finished(s, SSL3_ST_CR_FINISHED_A,
			    SSL3_ST_CR_FINISHED_B);
			if (ret <= 0)
				goto end;
			dtls1_stop_timer(s);

			if (s->internal->hit)
				S3I(s)->hs.state = SSL3_ST_CW_CHANGE_A;
			else
				S3I(s)->hs.state = SSL_ST_OK;


			s->internal->init_num = 0;
			break;

		case SSL3_ST_CW_FLUSH:
			s->internal->rwstate = SSL_WRITING;
			if (BIO_flush(s->wbio) <= 0) {
				/* If the write error was fatal, stop trying */
				if (!BIO_should_retry(s->wbio)) {
					s->internal->rwstate = SSL_NOTHING;
					S3I(s)->hs.state = S3I(s)->hs.next_state;
				}

				ret = -1;
				goto end;
			}
			s->internal->rwstate = SSL_NOTHING;
			S3I(s)->hs.state = S3I(s)->hs.next_state;
			break;

		case SSL_ST_OK:
			/* clean a few things up */
			tls1_cleanup_key_block(s);

			/* 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->internal->init_num = 0;
			s->internal->renegotiate = 0;
			s->internal->new_session = 0;

			ssl_update_cache(s, SSL_SESS_CACHE_CLIENT);
			if (s->internal->hit)
				s->ctx->internal->stats.sess_hit++;

			ret = 1;
			/* s->server=0; */
			s->internal->handshake_func = dtls1_connect;
			s->ctx->internal->stats.sess_connect_good++;

			if (cb != NULL)
				cb(s, SSL_CB_HANDSHAKE_DONE, 1);

			/* done with handshaking */
			D1I(s)->handshake_read_seq = 0;
			D1I(s)->next_handshake_write_seq = 0;
			goto end;
			/* break; */

		default:
			SSLerror(s, SSL_R_UNKNOWN_STATE);
			ret = -1;
			goto end;
			/* break; */
		}

		/* did we do anything */
		if (!S3I(s)->tmp.reuse_message && !skip) {
			if (s->internal->debug) {
				if ((ret = BIO_flush(s->wbio)) <= 0)
					goto end;
			}

			if ((cb != NULL) && (S3I(s)->hs.state != state)) {
				new_state = S3I(s)->hs.state;
				S3I(s)->hs.state = state;
				cb(s, SSL_CB_CONNECT_LOOP, 1);
				S3I(s)->hs.state = new_state;
			}
		}
		skip = 0;
	}

end:
	s->internal->in_handshake--;
	if (cb != NULL)
		cb(s, SSL_CB_CONNECT_EXIT, ret);

	return (ret);
}
示例#21
0
文件: tls.c 项目: JozLes77/FreeRDP
static long bio_rdp_tls_ctrl(BIO* bio, int cmd, long num, void* ptr)
{
	BIO* rbio;
	int status = -1;
	BIO_RDP_TLS* tls = (BIO_RDP_TLS*) bio->ptr;

	if (!tls)
		return 0;

	if (!tls->ssl && (cmd != BIO_C_SET_SSL))
		return 0;

	switch (cmd)
	{
		case BIO_CTRL_RESET:
			SSL_shutdown(tls->ssl);

			if (tls->ssl->handshake_func == tls->ssl->method->ssl_connect)
				SSL_set_connect_state(tls->ssl);
			else if (tls->ssl->handshake_func == tls->ssl->method->ssl_accept)
				SSL_set_accept_state(tls->ssl);

			SSL_clear(tls->ssl);

			if (bio->next_bio)
				status = BIO_ctrl(bio->next_bio, cmd, num, ptr);
			else if (tls->ssl->rbio)
				status = BIO_ctrl(tls->ssl->rbio, cmd, num, ptr);
			else
				status = 1;
			break;

		case BIO_C_GET_FD:
			status = BIO_ctrl(tls->ssl->rbio, cmd, num, ptr);
			break;

		case BIO_CTRL_INFO:
			status = 0;
			break;

		case BIO_CTRL_SET_CALLBACK:
			status = 0;
			break;

		case BIO_CTRL_GET_CALLBACK:
			*((ULONG_PTR*) ptr) = (ULONG_PTR) SSL_get_info_callback(tls->ssl);
			status = 1;
			break;

		case BIO_C_SSL_MODE:
			if (num)
				SSL_set_connect_state(tls->ssl);
			else
				SSL_set_accept_state(tls->ssl);
			status = 1;
			break;

		case BIO_CTRL_GET_CLOSE:
			status = bio->shutdown;
			break;

		case BIO_CTRL_SET_CLOSE:
			bio->shutdown = (int) num;
			status = 1;
			break;

		case BIO_CTRL_WPENDING:
			status = BIO_ctrl(tls->ssl->wbio, cmd, num, ptr);
			break;

		case BIO_CTRL_PENDING:
			status = SSL_pending(tls->ssl);
			if (status == 0)
				status = BIO_pending(tls->ssl->rbio);
			break;

		case BIO_CTRL_FLUSH:
			BIO_clear_retry_flags(bio);
			status = BIO_ctrl(tls->ssl->wbio, cmd, num, ptr);
			BIO_copy_next_retry(bio);
			status = 1;
			break;

		case BIO_CTRL_PUSH:
			if (bio->next_bio && (bio->next_bio != tls->ssl->rbio))
			{
				SSL_set_bio(tls->ssl, bio->next_bio, bio->next_bio);
				CRYPTO_add(&(bio->next_bio->references), 1, CRYPTO_LOCK_BIO);
			}
			status = 1;
			break;

		case BIO_CTRL_POP:
			if (bio == ptr)
			{
				if (tls->ssl->rbio != tls->ssl->wbio)
					BIO_free_all(tls->ssl->wbio);

				if (bio->next_bio)
					CRYPTO_add(&(bio->next_bio->references), -1, CRYPTO_LOCK_BIO);

				tls->ssl->wbio = tls->ssl->rbio = NULL;
			}
			status = 1;
			break;

		case BIO_C_GET_SSL:
			if (ptr)
			{
				*((SSL**) ptr) = tls->ssl;
				status = 1;
			}
			break;

		case BIO_C_SET_SSL:
			bio->shutdown = (int) num;

			if (ptr)
				tls->ssl = (SSL*) ptr;

			rbio = SSL_get_rbio(tls->ssl);

			if (rbio)
			{
				if (bio->next_bio)
					BIO_push(rbio, bio->next_bio);

				bio->next_bio = rbio;
				CRYPTO_add(&(rbio->references), 1, CRYPTO_LOCK_BIO);
			}

			bio->init = 1;
			status = 1;
			break;

		case BIO_C_DO_STATE_MACHINE:
			BIO_clear_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_WRITE | BIO_FLAGS_IO_SPECIAL);
			bio->retry_reason = 0;

			status = SSL_do_handshake(tls->ssl);

			if (status <= 0)
			{
				switch (SSL_get_error(tls->ssl, status))
				{
					case SSL_ERROR_WANT_READ:
						BIO_set_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY);
						break;

					case SSL_ERROR_WANT_WRITE:
						BIO_set_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY);
						break;

					case SSL_ERROR_WANT_CONNECT:
						BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY);
						bio->retry_reason = bio->next_bio->retry_reason;
						break;

					default:
						BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
						break;
				}
			}
			break;

		default:
			status = BIO_ctrl(tls->ssl->rbio, cmd, num, ptr);
			break;
	}

	return status;
}
示例#22
0
tb_long_t tb_ssl_clos_try(tb_ssl_ref_t self)
{
    // the ssl
    tb_ssl_t* ssl = (tb_ssl_t*)self;
    tb_assert_and_check_return_val(ssl, -1);

    // done
    tb_long_t ok = -1;
    do
    {
        // init state
        ssl->state = TB_STATE_OK;

        // have been closed already?
        if (!ssl->bopened || !ssl->ssl)
        {
            ok = 1;
            break;
        }

        // do shutdown
        tb_long_t r = SSL_shutdown(ssl->ssl);
    
        // trace
        tb_trace_d("clos: shutdown: %ld", r);

        // ok?
        if (r == 1) ok = 1;
        // continue?
        else if (!r) ok = 0;
        else
        {
            // the error
            tb_long_t error = SSL_get_error(ssl->ssl, r);

            // wait?
            if (error == SSL_ERROR_WANT_WRITE || error == SSL_ERROR_WANT_READ)
            {
                // trace
                tb_trace_d("clos: shutdown: wait: %s: ..", error == SSL_ERROR_WANT_READ? "read" : "writ");

                // continue it
                ok = 0;

                // save state
                ssl->state = (error == SSL_ERROR_WANT_READ)? TB_STATE_SOCK_SSL_WANT_READ : TB_STATE_SOCK_SSL_WANT_WRIT;
            }
            // failed?
            else
            {
                // trace
                tb_trace_d("clos: shutdown: failed: %s", tb_ssl_error(error));
    
                // save state
                ssl->state = TB_STATE_SOCK_SSL_FAILED;
            }
        }

    } while (0);

    // ok?
    if (ok > 0)
    {
        // closed
        ssl->bopened = tb_false;

        // clear ssl
        if (ssl->ssl) SSL_clear(ssl->ssl);
    }
    // failed?
    else if (ok < 0)
    {
        // save state
        if (ssl->state == TB_STATE_OK)
            ssl->state = TB_STATE_SOCK_SSL_FAILED;
    }

    // trace
    tb_trace_d("clos: shutdown: %s", ok > 0? "ok" : (!ok? ".." : "no"));

    // ok?
    return ok;
}
示例#23
0
static long ssl_ctrl(BIO *b, int cmd, long num, void *ptr)
	{
	SSL **sslp,*ssl;
	BIO_SSL *bs;
	BIO *dbio,*bio;
	long ret=1;

	bs=(BIO_SSL *)b->ptr;
	ssl=bs->ssl;
	if ((ssl == NULL)  && (cmd != BIO_C_SET_SSL))
		return(0);
	switch (cmd)
		{
	case BIO_CTRL_RESET:
		SSL_shutdown(ssl);

		if (ssl->handshake_func == ssl->method->ssl_connect)
			SSL_set_connect_state(ssl);
		else if (ssl->handshake_func == ssl->method->ssl_accept)
			SSL_set_accept_state(ssl);

		SSL_clear(ssl);

		if (b->next_bio != NULL)
			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
		else if (ssl->rbio != NULL)
			ret=BIO_ctrl(ssl->rbio,cmd,num,ptr);
		else
			ret=1;
		break;
	case BIO_CTRL_INFO:
		ret=0;
		break;
	case BIO_C_SSL_MODE:
		if (num) /* client mode */
			SSL_set_connect_state(ssl);
		else
			SSL_set_accept_state(ssl);
		break;
	case BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT:
		ret=bs->renegotiate_timeout;
		if (num < 60) num=5;
		bs->renegotiate_timeout=(unsigned long)num;
		bs->last_time=(unsigned long)time(NULL);
		break;
	case BIO_C_SET_SSL_RENEGOTIATE_BYTES:
		ret=bs->renegotiate_count;
		if ((long)num >=512)
			bs->renegotiate_count=(unsigned long)num;
		break;
	case BIO_C_GET_SSL_NUM_RENEGOTIATES:
		ret=bs->num_renegotiates;
		break;
	case BIO_C_SET_SSL:
		if (ssl != NULL)
			{
			ssl_free(b);
			if (!ssl_new(b))
				return 0;
			}
		b->shutdown=(int)num;
		ssl=(SSL *)ptr;
		((BIO_SSL *)b->ptr)->ssl=ssl;
		bio=SSL_get_rbio(ssl);
		if (bio != NULL)
			{
			if (b->next_bio != NULL)
				BIO_push(bio,b->next_bio);
			b->next_bio=bio;
			CRYPTO_add(&bio->references,1,CRYPTO_LOCK_BIO);
			}
		b->init=1;
		break;
	case BIO_C_GET_SSL:
		if (ptr != NULL)
			{
			sslp=(SSL **)ptr;
			*sslp=ssl;
			}
		else
			ret=0;
		break;
	case BIO_CTRL_GET_CLOSE:
		ret=b->shutdown;
		break;
	case BIO_CTRL_SET_CLOSE:
		b->shutdown=(int)num;
		break;
	case BIO_CTRL_WPENDING:
		ret=BIO_ctrl(ssl->wbio,cmd,num,ptr);
		break;
	case BIO_CTRL_PENDING:
		ret=SSL_pending(ssl);
		if (ret == 0)
			ret=BIO_pending(ssl->rbio);
		break;
	case BIO_CTRL_FLUSH:
		BIO_clear_retry_flags(b);
		ret=BIO_ctrl(ssl->wbio,cmd,num,ptr);
		BIO_copy_next_retry(b);
		break;
	case BIO_CTRL_PUSH:
		if ((b->next_bio != NULL) && (b->next_bio != ssl->rbio))
			{
			SSL_set_bio(ssl,b->next_bio,b->next_bio);
			CRYPTO_add(&b->next_bio->references,1,CRYPTO_LOCK_BIO);
			}
		break;
	case BIO_CTRL_POP:
		/* ugly bit of a hack */
		if (ssl->rbio != ssl->wbio) /* we are in trouble :-( */
			{
			BIO_free_all(ssl->wbio);
			}
		if (b->next_bio != NULL)
			{
			CRYPTO_add(&b->next_bio->references,1,CRYPTO_LOCK_BIO);
			}
		ssl->wbio=NULL;
		ssl->rbio=NULL;
		break;
	case BIO_C_DO_STATE_MACHINE:
		BIO_clear_retry_flags(b);

		b->retry_reason=0;
		ret=(int)SSL_do_handshake(ssl);

		switch (SSL_get_error(ssl,(int)ret))
			{
		case SSL_ERROR_WANT_READ:
			BIO_set_flags(b,
				BIO_FLAGS_READ|BIO_FLAGS_SHOULD_RETRY);
			break;
		case SSL_ERROR_WANT_WRITE:
			BIO_set_flags(b,
				BIO_FLAGS_WRITE|BIO_FLAGS_SHOULD_RETRY);
			break;
		case SSL_ERROR_WANT_CONNECT:
			BIO_set_flags(b,
				BIO_FLAGS_IO_SPECIAL|BIO_FLAGS_SHOULD_RETRY);
			b->retry_reason=b->next_bio->retry_reason;
			break;
		default:
			break;
			}
		break;
	case BIO_CTRL_DUP:
		dbio=(BIO *)ptr;
		if (((BIO_SSL *)dbio->ptr)->ssl != NULL)
			SSL_free(((BIO_SSL *)dbio->ptr)->ssl);
		((BIO_SSL *)dbio->ptr)->ssl=SSL_dup(ssl);
		((BIO_SSL *)dbio->ptr)->renegotiate_count=
			((BIO_SSL *)b->ptr)->renegotiate_count;
		((BIO_SSL *)dbio->ptr)->byte_count=
			((BIO_SSL *)b->ptr)->byte_count;
		((BIO_SSL *)dbio->ptr)->renegotiate_timeout=
			((BIO_SSL *)b->ptr)->renegotiate_timeout;
		((BIO_SSL *)dbio->ptr)->last_time=
			((BIO_SSL *)b->ptr)->last_time;
		ret=(((BIO_SSL *)dbio->ptr)->ssl != NULL);
		break;
	case BIO_C_GET_FD:
		ret=BIO_ctrl(ssl->rbio,cmd,num,ptr);
		break;
	case BIO_CTRL_SET_CALLBACK:
		{
#if 0 /* FIXME: Should this be used?  -- Richard Levitte */
		SSLerr(SSL_F_SSL_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
		ret = -1;
#else
		ret=0;
#endif
		}
		break;
	case BIO_CTRL_GET_CALLBACK:
		{
		void (**fptr)(const SSL *xssl,int type,int val);

		fptr=(void (**)(const SSL *xssl,int type,int val))ptr;
		*fptr=SSL_get_info_callback(ssl);
		}
		break;
	default:
		ret=BIO_ctrl(ssl->rbio,cmd,num,ptr);
		break;
		}
	return(ret);
	}
示例#24
0
int
dtls1_accept(SSL *s)
{
	void (*cb)(const SSL *ssl, int type, int val) = NULL;
	unsigned long alg_k;
	int ret = -1;
	int new_state, state, skip = 0;
	int listen;
#ifndef OPENSSL_NO_SCTP
	unsigned char sctpauthkey[64];
	char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
#endif

	ERR_clear_error();
	errno = 0;

	if (s->info_callback != NULL)
		cb = s->info_callback;
	else if (s->ctx->info_callback != NULL)
		cb = s->ctx->info_callback;

	listen = s->d1->listen;

	/* init things to blank */
	s->in_handshake++;
	if (!SSL_in_init(s) || SSL_in_before(s))
		SSL_clear(s);

	s->d1->listen = listen;
#ifndef OPENSSL_NO_SCTP
	/* Notify SCTP BIO socket to enter handshake
	 * mode and prevent stream identifier other
	 * than 0. Will be ignored if no SCTP is used.
	 */
	BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE,
	    s->in_handshake, NULL);
#endif

	if (s->cert == NULL) {
		SSLerr(SSL_F_DTLS1_ACCEPT, SSL_R_NO_CERTIFICATE_SET);
		return (-1);
	}

	for (;;) {
		state = s->state;

		switch (s->state) {
		case SSL_ST_RENEGOTIATE:
			s->renegotiate = 1;
			/* s->state=SSL_ST_ACCEPT; */

		case SSL_ST_BEFORE:
		case SSL_ST_ACCEPT:
		case SSL_ST_BEFORE|SSL_ST_ACCEPT:
		case SSL_ST_OK|SSL_ST_ACCEPT:

			s->server = 1;
			if (cb != NULL)
				cb(s, SSL_CB_HANDSHAKE_START, 1);

			if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00)) {
				SSLerr(SSL_F_DTLS1_ACCEPT, ERR_R_INTERNAL_ERROR);
				return -1;
			}
			s->type = SSL_ST_ACCEPT;

			if (s->init_buf == NULL) {
				BUF_MEM *buf;
				if ((buf = BUF_MEM_new()) == NULL) {
					ret = -1;
					goto end;
				}
				if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
					BUF_MEM_free(buf);
					ret = -1;
					goto end;
				}
				s->init_buf = buf;
			}

			if (!ssl3_setup_buffers(s)) {
				ret = -1;
				goto end;
			}

			s->init_num = 0;

			if (s->state != SSL_ST_RENEGOTIATE) {
				/* Ok, we now need to push on a buffering BIO so that
				 * the output is sent in a way that TCP likes :-)
				 * ...but not with SCTP :-)
				 */
#ifndef OPENSSL_NO_SCTP
				if (!BIO_dgram_is_sctp(SSL_get_wbio(s)))
#endif
				if (!ssl_init_wbio_buffer(s, 1)) {
					ret = -1;
					goto end;
				}

				ssl3_init_finished_mac(s);
				s->state = SSL3_ST_SR_CLNT_HELLO_A;
				s->ctx->stats.sess_accept++;
			} else {
				/* s->state == SSL_ST_RENEGOTIATE,
				 * we will just send a HelloRequest */
				s->ctx->stats.sess_accept_renegotiate++;
				s->state = SSL3_ST_SW_HELLO_REQ_A;
			}

			break;

		case SSL3_ST_SW_HELLO_REQ_A:
		case SSL3_ST_SW_HELLO_REQ_B:

			s->shutdown = 0;
			dtls1_clear_record_buffer(s);
			dtls1_start_timer(s);
			ret = dtls1_send_hello_request(s);
			if (ret <= 0)
				goto end;
			s->s3->tmp.next_state = SSL3_ST_SR_CLNT_HELLO_A;
			s->state = SSL3_ST_SW_FLUSH;
			s->init_num = 0;

			ssl3_init_finished_mac(s);
			break;

		case SSL3_ST_SW_HELLO_REQ_C:
			s->state = SSL_ST_OK;
			break;

		case SSL3_ST_SR_CLNT_HELLO_A:
		case SSL3_ST_SR_CLNT_HELLO_B:
		case SSL3_ST_SR_CLNT_HELLO_C:

			s->shutdown = 0;
			ret = ssl3_get_client_hello(s);
			if (ret <= 0)
				goto end;
			dtls1_stop_timer(s);

			if (ret == 1 && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE))
				s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A;
			else
				s->state = SSL3_ST_SW_SRVR_HELLO_A;

			s->init_num = 0;

			/* Reflect ClientHello sequence to remain stateless while listening */
			if (listen) {
				memcpy(s->s3->write_sequence, s->s3->read_sequence, sizeof(s->s3->write_sequence));
			}

			/* If we're just listening, stop here */
			if (listen && s->state == SSL3_ST_SW_SRVR_HELLO_A) {
				ret = 2;
				s->d1->listen = 0;
				/* Set expected sequence numbers
				 * to continue the handshake.
				 */
				s->d1->handshake_read_seq = 2;
				s->d1->handshake_write_seq = 1;
				s->d1->next_handshake_write_seq = 1;
				goto end;
			}

			break;

		case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A:
		case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B:

			ret = dtls1_send_hello_verify_request(s);
			if (ret <= 0)
				goto end;
			s->state = SSL3_ST_SW_FLUSH;
			s->s3->tmp.next_state = SSL3_ST_SR_CLNT_HELLO_A;

			/* HelloVerifyRequest resets Finished MAC */
			if (s->version != DTLS1_BAD_VER)
				ssl3_init_finished_mac(s);
			break;

#ifndef OPENSSL_NO_SCTP
		case DTLS1_SCTP_ST_SR_READ_SOCK:

			if (BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
				s->s3->in_read_app_data = 2;
				s->rwstate = SSL_READING;
				BIO_clear_retry_flags(SSL_get_rbio(s));
				BIO_set_retry_read(SSL_get_rbio(s));
				ret = -1;
				goto end;
			}

			s->state = SSL3_ST_SR_FINISHED_A;
			break;

		case DTLS1_SCTP_ST_SW_WRITE_SOCK:
			ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s));
			if (ret < 0)
				goto end;

			if (ret == 0) {
				if (s->d1->next_state != SSL_ST_OK) {
					s->s3->in_read_app_data = 2;
					s->rwstate = SSL_READING;
					BIO_clear_retry_flags(SSL_get_rbio(s));
					BIO_set_retry_read(SSL_get_rbio(s));
					ret = -1;
					goto end;
				}
			}

			s->state = s->d1->next_state;
			break;
#endif

		case SSL3_ST_SW_SRVR_HELLO_A:
		case SSL3_ST_SW_SRVR_HELLO_B:
			s->renegotiate = 2;
			dtls1_start_timer(s);
			ret = dtls1_send_server_hello(s);
			if (ret <= 0)
				goto end;

			if (s->hit) {
#ifndef OPENSSL_NO_SCTP
				/* Add new shared key for SCTP-Auth,
				 * will be ignored if no SCTP used.
				 */
				snprintf((char*)labelbuffer,
				    sizeof(DTLS1_SCTP_AUTH_LABEL),
				    DTLS1_SCTP_AUTH_LABEL);

				SSL_export_keying_material(s, sctpauthkey,
				    sizeof(sctpauthkey), labelbuffer,
				    sizeof(labelbuffer), NULL, 0, 0);

				BIO_ctrl(SSL_get_wbio(s),
				    BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
				    sizeof(sctpauthkey), sctpauthkey);
#endif
				if (s->tlsext_ticket_expected)
					s->state = SSL3_ST_SW_SESSION_TICKET_A;
				else
					s->state = SSL3_ST_SW_CHANGE_A;
			} else
				s->state = SSL3_ST_SW_CERT_A;
			s->init_num = 0;
			break;

		case SSL3_ST_SW_CERT_A:
		case SSL3_ST_SW_CERT_B:
			/* Check if it is anon DH or normal PSK */
			if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
			    !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) {
				dtls1_start_timer(s);
				ret = dtls1_send_server_certificate(s);
				if (ret <= 0)
					goto end;
				if (s->tlsext_status_expected)
					s->state = SSL3_ST_SW_CERT_STATUS_A;
				else
					s->state = SSL3_ST_SW_KEY_EXCH_A;
			} else {
				skip = 1;
				s->state = SSL3_ST_SW_KEY_EXCH_A;
			}
			s->init_num = 0;
			break;

		case SSL3_ST_SW_KEY_EXCH_A:
		case SSL3_ST_SW_KEY_EXCH_B:
			alg_k = s->s3->tmp.new_cipher->algorithm_mkey;

			/* clear this, it may get reset by
			 * send_server_key_exchange */
			if ((s->options & SSL_OP_EPHEMERAL_RSA)
			)
				/* option SSL_OP_EPHEMERAL_RSA sends temporary RSA key
				 * even when forbidden by protocol specs
				 * (handshake may fail as clients are not required to
				 * be able to handle this) */
				s->s3->tmp.use_rsa_tmp = 1;
			else
				s->s3->tmp.use_rsa_tmp = 0;

			/* only send if a DH key exchange or
			 * RSA but we have a sign only certificate */
			if (s->s3->tmp.use_rsa_tmp
			|| (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
			|| (alg_k & SSL_kEECDH)
			|| ((alg_k & SSL_kRSA)
			&& (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
			)
			)
			) {
				dtls1_start_timer(s);
				ret = dtls1_send_server_key_exchange(s);
				if (ret <= 0)
					goto end;
			} else
				skip = 1;

			s->state = SSL3_ST_SW_CERT_REQ_A;
			s->init_num = 0;
			break;

		case SSL3_ST_SW_CERT_REQ_A:
		case SSL3_ST_SW_CERT_REQ_B:
			if (/* don't request cert unless asked for it: */
			    !(s->verify_mode & SSL_VERIFY_PEER) ||
				/* if SSL_VERIFY_CLIENT_ONCE is set,
				 * don't request cert during re-negotiation: */
			    ((s->session->peer != NULL) &&
			    (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) ||
				/* never request cert in anonymous ciphersuites
				 * (see section "Certificate request" in SSL 3 drafts
				 * and in RFC 2246): */
			    ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
				 /* ... except when the application insists on verification
				  * (against the specs, but s3_clnt.c accepts this for SSL 3) */
			    !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) ||
				/* never request cert in Kerberos ciphersuites */
			    (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5)
				/* With normal PSK Certificates and
				 * Certificate Requests are omitted */
			    || (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) {
				/* no cert request */
				skip = 1;
				s->s3->tmp.cert_request = 0;
				s->state = SSL3_ST_SW_SRVR_DONE_A;
#ifndef OPENSSL_NO_SCTP
				if (BIO_dgram_is_sctp(SSL_get_wbio(s))) {
					s->d1->next_state = SSL3_ST_SW_SRVR_DONE_A;
					s->state = DTLS1_SCTP_ST_SW_WRITE_SOCK;
				}
#endif
			} else {
				s->s3->tmp.cert_request = 1;
				dtls1_start_timer(s);
				ret = dtls1_send_certificate_request(s);
				if (ret <= 0)
					goto end;
#ifndef NETSCAPE_HANG_BUG
				s->state = SSL3_ST_SW_SRVR_DONE_A;
#ifndef OPENSSL_NO_SCTP
				if (BIO_dgram_is_sctp(SSL_get_wbio(s))) {
					s->d1->next_state = SSL3_ST_SW_SRVR_DONE_A;
					s->state = DTLS1_SCTP_ST_SW_WRITE_SOCK;
				}
#endif
#else
				s->state = SSL3_ST_SW_FLUSH;
				s->s3->tmp.next_state = SSL3_ST_SR_CERT_A;
#ifndef OPENSSL_NO_SCTP
				if (BIO_dgram_is_sctp(SSL_get_wbio(s))) {
					s->d1->next_state = s->s3->tmp.next_state;
					s->s3->tmp.next_state = DTLS1_SCTP_ST_SW_WRITE_SOCK;
				}
#endif
#endif
				s->init_num = 0;
			}
			break;

		case SSL3_ST_SW_SRVR_DONE_A:
		case SSL3_ST_SW_SRVR_DONE_B:
			dtls1_start_timer(s);
			ret = dtls1_send_server_done(s);
			if (ret <= 0)
				goto end;
			s->s3->tmp.next_state = SSL3_ST_SR_CERT_A;
			s->state = SSL3_ST_SW_FLUSH;
			s->init_num = 0;
			break;

		case SSL3_ST_SW_FLUSH:
			s->rwstate = SSL_WRITING;
			if (BIO_flush(s->wbio) <= 0) {
				/* If the write error was fatal, stop trying */
				if (!BIO_should_retry(s->wbio)) {
					s->rwstate = SSL_NOTHING;
					s->state = s->s3->tmp.next_state;
				}

				ret = -1;
				goto end;
			}
			s->rwstate = SSL_NOTHING;
			s->state = s->s3->tmp.next_state;
			break;

		case SSL3_ST_SR_CERT_A:
		case SSL3_ST_SR_CERT_B:
			/* Check for second client hello (MS SGC) */
			ret = ssl3_check_client_hello(s);
			if (ret <= 0)
				goto end;
			if (ret == 2) {
				dtls1_stop_timer(s);
				s->state = SSL3_ST_SR_CLNT_HELLO_C;
			} else {
				/* could be sent for a DH cert, even if we
				 * have not asked for it :-) */
				ret = ssl3_get_client_certificate(s);
				if (ret <= 0)
					goto end;
				s->init_num = 0;
				s->state = SSL3_ST_SR_KEY_EXCH_A;
			}
			break;

		case SSL3_ST_SR_KEY_EXCH_A:
		case SSL3_ST_SR_KEY_EXCH_B:
			ret = ssl3_get_client_key_exchange(s);
			if (ret <= 0)
				goto end;
#ifndef OPENSSL_NO_SCTP
			/* Add new shared key for SCTP-Auth,
			 * will be ignored if no SCTP used.
			 */
			snprintf((char *)labelbuffer,
			    sizeof(DTLS1_SCTP_AUTH_LABEL),
			    DTLS1_SCTP_AUTH_LABEL);

			SSL_export_keying_material(s, sctpauthkey,
			    sizeof(sctpauthkey), labelbuffer,
			    sizeof(labelbuffer), NULL, 0, 0);

			BIO_ctrl(SSL_get_wbio(s),
			    BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
			    sizeof(sctpauthkey), sctpauthkey);
#endif

			s->state = SSL3_ST_SR_CERT_VRFY_A;
			s->init_num = 0;

			if (ret == 2) {
				/* For the ECDH ciphersuites when
				 * the client sends its ECDH pub key in
				 * a certificate, the CertificateVerify
				 * message is not sent.
				 */
				s->state = SSL3_ST_SR_FINISHED_A;
				s->init_num = 0;
			} else {
				s->state = SSL3_ST_SR_CERT_VRFY_A;
				s->init_num = 0;

				/* We need to get hashes here so if there is
				 * a client cert, it can be verified */ 
				s->method->ssl3_enc->cert_verify_mac(s,
				    NID_md5, &(s->s3->tmp.cert_verify_md[0]));
				s->method->ssl3_enc->cert_verify_mac(s,
				    NID_sha1,
				    &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]));
			}
			break;

		case SSL3_ST_SR_CERT_VRFY_A:
		case SSL3_ST_SR_CERT_VRFY_B:

			s->d1->change_cipher_spec_ok = 1;
			/* we should decide if we expected this one */
			ret = ssl3_get_cert_verify(s);
			if (ret <= 0)
				goto end;
#ifndef OPENSSL_NO_SCTP
			if (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
			    state == SSL_ST_RENEGOTIATE)
				s->state = DTLS1_SCTP_ST_SR_READ_SOCK;
			else
#endif			
				s->state = SSL3_ST_SR_FINISHED_A;
			s->init_num = 0;
			break;

		case SSL3_ST_SR_FINISHED_A:
		case SSL3_ST_SR_FINISHED_B:
			s->d1->change_cipher_spec_ok = 1;
			ret = ssl3_get_finished(s, SSL3_ST_SR_FINISHED_A,
			SSL3_ST_SR_FINISHED_B);
			if (ret <= 0)
				goto end;
			dtls1_stop_timer(s);
			if (s->hit)
				s->state = SSL_ST_OK;
			else if (s->tlsext_ticket_expected)
				s->state = SSL3_ST_SW_SESSION_TICKET_A;
			else
				s->state = SSL3_ST_SW_CHANGE_A;
			s->init_num = 0;
			break;

		case SSL3_ST_SW_SESSION_TICKET_A:
		case SSL3_ST_SW_SESSION_TICKET_B:
			ret = dtls1_send_newsession_ticket(s);
			if (ret <= 0)
				goto end;
			s->state = SSL3_ST_SW_CHANGE_A;
			s->init_num = 0;
			break;

		case SSL3_ST_SW_CERT_STATUS_A:
		case SSL3_ST_SW_CERT_STATUS_B:
			ret = ssl3_send_cert_status(s);
			if (ret <= 0)
				goto end;
			s->state = SSL3_ST_SW_KEY_EXCH_A;
			s->init_num = 0;
			break;


		case SSL3_ST_SW_CHANGE_A:
		case SSL3_ST_SW_CHANGE_B:

			s->session->cipher = s->s3->tmp.new_cipher;
			if (!s->method->ssl3_enc->setup_key_block(s)) {
				ret = -1;
				goto end;
			}

			ret = dtls1_send_change_cipher_spec(s,
			SSL3_ST_SW_CHANGE_A, SSL3_ST_SW_CHANGE_B);

			if (ret <= 0)
				goto end;

#ifndef OPENSSL_NO_SCTP
			if (!s->hit) {
				/* Change to new shared key of SCTP-Auth,
				 * will be ignored if no SCTP used.
				 */
				BIO_ctrl(SSL_get_wbio(s),
				    BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, 0, NULL);
			}
#endif

			s->state = SSL3_ST_SW_FINISHED_A;
			s->init_num = 0;

			if (!s->method->ssl3_enc->change_cipher_state(s,
				SSL3_CHANGE_CIPHER_SERVER_WRITE)) {
				ret = -1;
				goto end;
			}

			dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
			break;

		case SSL3_ST_SW_FINISHED_A:
		case SSL3_ST_SW_FINISHED_B:
			ret = dtls1_send_finished(s,
			    SSL3_ST_SW_FINISHED_A, SSL3_ST_SW_FINISHED_B,
			    s->method->ssl3_enc->server_finished_label,
			    s->method->ssl3_enc->server_finished_label_len);
			if (ret <= 0)
				goto end;
			s->state = SSL3_ST_SW_FLUSH;
			if (s->hit) {
				s->s3->tmp.next_state = SSL3_ST_SR_FINISHED_A;

#ifndef OPENSSL_NO_SCTP
				/* Change to new shared key of SCTP-Auth,
				 * will be ignored if no SCTP used.
				 */
				BIO_ctrl(SSL_get_wbio(s),
				    BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, 0, NULL);
#endif
			} else {
				s->s3->tmp.next_state = SSL_ST_OK;
#ifndef OPENSSL_NO_SCTP
				if (BIO_dgram_is_sctp(SSL_get_wbio(s))) {
					s->d1->next_state = s->s3->tmp.next_state;
					s->s3->tmp.next_state = DTLS1_SCTP_ST_SW_WRITE_SOCK;
				}
#endif
			}
			s->init_num = 0;
			break;

		case SSL_ST_OK:
			/* clean a few things up */
			ssl3_cleanup_key_block(s);

			/* remove buffering on output */
			ssl_free_wbio_buffer(s);

			s->init_num = 0;

			if (s->renegotiate == 2) /* skipped if we just sent a HelloRequest */
			{
				s->renegotiate = 0;
				s->new_session = 0;

				ssl_update_cache(s, SSL_SESS_CACHE_SERVER);

				s->ctx->stats.sess_accept_good++;
				/* s->server=1; */
				s->handshake_func = dtls1_accept;

				if (cb != NULL)
					cb(s, SSL_CB_HANDSHAKE_DONE, 1);
			}

			ret = 1;

			/* done handshaking, next message is client hello */
			s->d1->handshake_read_seq = 0;
			/* next message is server hello */
			s->d1->handshake_write_seq = 0;
			s->d1->next_handshake_write_seq = 0;
			goto end;
			/* break; */

		default:
			SSLerr(SSL_F_DTLS1_ACCEPT, SSL_R_UNKNOWN_STATE);
			ret = -1;
			goto end;
			/* break; */
		}

		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_ACCEPT_LOOP, 1);
				s->state = new_state;
			}
		}
		skip = 0;
	}
end:
	/* BIO_flush(s->wbio); */

	s->in_handshake--;
#ifndef OPENSSL_NO_SCTP
	/* Notify SCTP BIO socket to leave handshake
	 * mode and prevent stream identifier other
	 * than 0. Will be ignored if no SCTP is used.
	 */
	BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE,
	    s->in_handshake, NULL);
#endif

	if (cb != NULL)
		cb(s, SSL_CB_ACCEPT_EXIT, ret);
	return (ret);
}
示例#25
0
int sslconnect(struct st_VioSSLFd *ptr, Vio *vio, long timeout)
{
  SSL *ssl;
  my_bool unused;
  my_bool was_blocking;

  DBUG_ENTER("sslconnect");
  DBUG_PRINT("enter", ("ptr: 0x%lx, sd: %d  ctx: 0x%lx",
                       (long) ptr, vio->sd, (long) ptr->ssl_context));

  /* Set socket to blocking if not already set */
  vio_blocking(vio, 1, &was_blocking);

  if (!(ssl= SSL_new(ptr->ssl_context)))
  {
    DBUG_PRINT("error", ("SSL_new failure"));
    report_errors(ssl);
    vio_blocking(vio, was_blocking, &unused);
    DBUG_RETURN(1);
  }
  DBUG_PRINT("info", ("ssl: 0x%lx timeout: %ld", (long) ssl, timeout));
  SSL_clear(ssl);
  SSL_SESSION_set_timeout(SSL_get_session(ssl), timeout);
  SSL_set_fd(ssl, vio->sd);

  /*
    SSL_do_handshake will select between SSL_connect
    or SSL_accept depending on server or client side
  */
  if (SSL_do_handshake(ssl) < 1)
  {
    DBUG_PRINT("error", ("SSL_do_handshake failure"));
    report_errors(ssl);
    SSL_free(ssl);
    vio_blocking(vio, was_blocking, &unused);
    DBUG_RETURN(1);
  }

  /*
    Connection succeeded. Install new function handlers,
    change type, set sd to the fd used when connecting
    and set pointer to the SSL structure
  */
  vio_reset(vio, VIO_TYPE_SSL, SSL_get_fd(ssl), 0, 0);
  vio->ssl_arg= (void*)ssl;

#ifndef DBUG_OFF
  {
    /* Print some info about the peer */
    X509 *cert;
    char buf[512];

    DBUG_PRINT("info",("SSL connection succeeded"));
    DBUG_PRINT("info",("Using cipher: '%s'" , SSL_get_cipher_name(ssl)));

    if ((cert= SSL_get_peer_certificate (ssl)))
    {
      DBUG_PRINT("info",("Peer certificate:"));
      X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
      DBUG_PRINT("info",("\t subject: '%s'", buf));
      X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf));
      DBUG_PRINT("info",("\t issuer: '%s'", buf));
      X509_free(cert);
    }
    else
      DBUG_PRINT("info",("Peer does not have certificate."));

    if (SSL_get_shared_ciphers(ssl, buf, sizeof(buf)))
    {
      DBUG_PRINT("info",("shared_ciphers: '%s'", buf));
    }
    else
      DBUG_PRINT("info",("no shared ciphers!"));
  }
#endif

  DBUG_RETURN(0);
}
int dtls1_accept(SSL *s)
	{
	BUF_MEM *buf;
	void (*cb)(const SSL *ssl,int type,int val)=NULL;
	unsigned long alg_a;
	int ret= -1;
	int new_state,state,skip=0;
	int listen;

	ERR_clear_error();
	ERR_clear_system_error();

	if (s->info_callback != NULL)
		cb=s->info_callback;
	else if (s->ctx->info_callback != NULL)
		cb=s->ctx->info_callback;
	
	listen = s->d1->listen;

	/* init things to blank */
	s->in_handshake++;
	if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);

	s->d1->listen = listen;

	if (s->cert == NULL)
		{
		OPENSSL_PUT_ERROR(SSL, dtls1_accept, SSL_R_NO_CERTIFICATE_SET);
		return(-1);
		}

	for (;;)
		{
		state=s->state;

		switch (s->state)
			{
		case SSL_ST_RENEGOTIATE:
			s->renegotiate=1;
			/* s->state=SSL_ST_ACCEPT; */

		case SSL_ST_BEFORE:
		case SSL_ST_ACCEPT:
		case SSL_ST_BEFORE|SSL_ST_ACCEPT:
		case SSL_ST_OK|SSL_ST_ACCEPT:

			s->server=1;
			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);

			if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00))
				{
				OPENSSL_PUT_ERROR(SSL, dtls1_accept, ERR_R_INTERNAL_ERROR);
				return -1;
				}
			s->type=SSL_ST_ACCEPT;

			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;
				}

			if (!ssl3_setup_buffers(s))
				{
				ret= -1;
				goto end;
				}

			s->init_num=0;

			if (s->state != SSL_ST_RENEGOTIATE)
				{
				/* Ok, we now need to push on a buffering BIO so that
				 * the output is sent in a way that TCP likes :-)
				 * ...but not with SCTP :-)
				 */
					if (!ssl_init_wbio_buffer(s,1)) { ret= -1; goto end; }

				ssl3_init_finished_mac(s);
				s->state=SSL3_ST_SR_CLNT_HELLO_A;
				s->ctx->stats.sess_accept++;
				}
			else
				{
				/* s->state == SSL_ST_RENEGOTIATE,
				 * we will just send a HelloRequest */
				s->ctx->stats.sess_accept_renegotiate++;
				s->state=SSL3_ST_SW_HELLO_REQ_A;
				}

			break;

		case SSL3_ST_SW_HELLO_REQ_A:
		case SSL3_ST_SW_HELLO_REQ_B:

			s->shutdown=0;
			dtls1_clear_record_buffer(s);
			dtls1_start_timer(s);
			ret=ssl3_send_hello_request(s);
			if (ret <= 0) goto end;
			s->s3->tmp.next_state=SSL3_ST_SR_CLNT_HELLO_A;
			s->state=SSL3_ST_SW_FLUSH;
			s->init_num=0;

			ssl3_init_finished_mac(s);
			break;

		case SSL3_ST_SW_HELLO_REQ_C:
			s->state=SSL_ST_OK;
			break;

		case SSL3_ST_SR_CLNT_HELLO_A:
		case SSL3_ST_SR_CLNT_HELLO_B:
		case SSL3_ST_SR_CLNT_HELLO_C:
		case SSL3_ST_SR_CLNT_HELLO_D:

			s->shutdown=0;
			ret=ssl3_get_client_hello(s);
			if (ret <= 0) goto end;
			dtls1_stop_timer(s);

			if (ret == 1 && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE))
				s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A;
			else
				s->state = SSL3_ST_SW_SRVR_HELLO_A;

			s->init_num=0;

			/* Reflect ClientHello sequence to remain stateless while listening */
			if (listen)
				{
				memcpy(s->s3->write_sequence, s->s3->read_sequence, sizeof(s->s3->write_sequence));
				}

			/* If we're just listening, stop here */
			if (listen && s->state == SSL3_ST_SW_SRVR_HELLO_A)
				{
				ret = 2;
				s->d1->listen = 0;
				/* Set expected sequence numbers
				 * to continue the handshake.
				 */
				s->d1->handshake_read_seq = 2;
				s->d1->handshake_write_seq = 1;
				s->d1->next_handshake_write_seq = 1;
				goto end;
				}
			
			break;
			
		case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A:
		case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B:

			ret = dtls1_send_hello_verify_request(s);
			if ( ret <= 0) goto end;
			s->state=SSL3_ST_SW_FLUSH;
			s->s3->tmp.next_state=SSL3_ST_SR_CLNT_HELLO_A;

			/* HelloVerifyRequest resets Finished MAC */
			ssl3_init_finished_mac(s);
			break;
			

		case SSL3_ST_SW_SRVR_HELLO_A:
		case SSL3_ST_SW_SRVR_HELLO_B:
			s->renegotiate = 2;
			dtls1_start_timer(s);
			ret=ssl3_send_server_hello(s);
			if (ret <= 0) goto end;

			if (s->hit)
				{
				if (s->tlsext_ticket_expected)
					s->state=SSL3_ST_SW_SESSION_TICKET_A;
				else
					s->state=SSL3_ST_SW_CHANGE_A;
				}
			else
				s->state=SSL3_ST_SW_CERT_A;
			s->init_num=0;
			break;

		case SSL3_ST_SW_CERT_A:
		case SSL3_ST_SW_CERT_B:
			/* Check if it is anon DH or normal PSK */
			if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
				&& !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
				{
				dtls1_start_timer(s);
				ret=ssl3_send_server_certificate(s);
				if (ret <= 0) goto end;
				if (s->tlsext_status_expected)
					s->state=SSL3_ST_SW_CERT_STATUS_A;
				else
					s->state=SSL3_ST_SW_KEY_EXCH_A;
				}
			else
				{
				skip = 1;
				s->state=SSL3_ST_SW_KEY_EXCH_A;
				}
			s->init_num=0;
			break;

		case SSL3_ST_SW_KEY_EXCH_A:
		case SSL3_ST_SW_KEY_EXCH_B:
			alg_a = s->s3->tmp.new_cipher->algorithm_auth;

			/* Send a ServerKeyExchange message if:
			 * - The key exchange is ephemeral or anonymous
			 *   Diffie-Hellman.
			 * - There is a PSK identity hint.
			 *
			 * TODO(davidben): This logic is currently duplicated
			 * in s3_srvr.c. Fix this. In the meantime, keep them
			 * in sync.
			 */
			if (ssl_cipher_requires_server_key_exchange(s->s3->tmp.new_cipher) ||
			    ((alg_a & SSL_aPSK) && s->session->psk_identity_hint))
				{
				dtls1_start_timer(s);
				ret=ssl3_send_server_key_exchange(s);
				if (ret <= 0) goto end;
				}
			else
				skip=1;

			s->state=SSL3_ST_SW_CERT_REQ_A;
			s->init_num=0;
			break;

		case SSL3_ST_SW_CERT_REQ_A:
		case SSL3_ST_SW_CERT_REQ_B:
			if (/* don't request cert unless asked for it: */
				!(s->verify_mode & SSL_VERIFY_PEER) ||
				/* if SSL_VERIFY_CLIENT_ONCE is set,
				 * don't request cert during re-negotiation: */
				((s->session->peer != NULL) &&
				 (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) ||
				/* never request cert in anonymous ciphersuites
				 * (see section "Certificate request" in SSL 3 drafts
				 * and in RFC 2246): */
				((s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
				 /* ... except when the application insists on verification
				  * (against the specs, but s3_clnt.c accepts this for SSL 3) */
				 !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) ||
				/* With normal PSK Certificates and
				 * Certificate Requests are omitted */
				(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
				{
				/* no cert request */
				skip=1;
				s->s3->tmp.cert_request=0;
				s->state=SSL3_ST_SW_SRVR_DONE_A;
				}
			else
				{
				s->s3->tmp.cert_request=1;
				dtls1_start_timer(s);
				ret=ssl3_send_certificate_request(s);
				if (ret <= 0) goto end;
#ifndef NETSCAPE_HANG_BUG
				s->state=SSL3_ST_SW_SRVR_DONE_A;
#else
				s->state=SSL3_ST_SW_FLUSH;
				s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
#endif
				s->init_num=0;
				}
			break;

		case SSL3_ST_SW_SRVR_DONE_A:
		case SSL3_ST_SW_SRVR_DONE_B:
			dtls1_start_timer(s);
			ret=ssl3_send_server_done(s);
			if (ret <= 0) goto end;
			s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
			s->state=SSL3_ST_SW_FLUSH;
			s->init_num=0;
			break;
		
		case SSL3_ST_SW_FLUSH:
			s->rwstate=SSL_WRITING;
			if (BIO_flush(s->wbio) <= 0)
				{
				/* If the write error was fatal, stop trying */
				if (!BIO_should_retry(s->wbio))
					{
					s->rwstate=SSL_NOTHING;
					s->state=s->s3->tmp.next_state;
					}
				
				ret= -1;
				goto end;
				}
			s->rwstate=SSL_NOTHING;
			s->state=s->s3->tmp.next_state;
			break;

		case SSL3_ST_SR_CERT_A:
		case SSL3_ST_SR_CERT_B:
			if (s->s3->tmp.cert_request)
				{
				ret=ssl3_get_client_certificate(s);
				if (ret <= 0) goto end;
				}
			s->init_num=0;
			s->state=SSL3_ST_SR_KEY_EXCH_A;
			break;

		case SSL3_ST_SR_KEY_EXCH_A:
		case SSL3_ST_SR_KEY_EXCH_B:
			ret=ssl3_get_client_key_exchange(s);
			if (ret <= 0)
				goto end;
			s->state=SSL3_ST_SR_CERT_VRFY_A;
			s->init_num=0;

			/* TODO(davidben): These two blocks are different
			 * between SSL and DTLS. Resolve the difference and code
			 * duplication. */
			if (SSL_USE_SIGALGS(s))
				{
				if (!s->session->peer)
					break;
				/* For sigalgs freeze the handshake buffer
				 * at this point and digest cached records.
				 */
				if (!s->s3->handshake_buffer)
					{
					OPENSSL_PUT_ERROR(SSL, dtls1_accept, ERR_R_INTERNAL_ERROR);
					return -1;
					}
				s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE;
				if (!ssl3_digest_cached_records(s))
					return -1;
				}
			else
				{
				/* We need to get hashes here so if there is
				 * a client cert, it can be verified */ 
				s->method->ssl3_enc->cert_verify_mac(s,
					NID_md5,
					&(s->s3->tmp.cert_verify_md[0]));
				s->method->ssl3_enc->cert_verify_mac(s,
					NID_sha1,
					&(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]));
				}
			break;

		case SSL3_ST_SR_CERT_VRFY_A:
		case SSL3_ST_SR_CERT_VRFY_B:

			s->d1->change_cipher_spec_ok = 1;
			/* we should decide if we expected this one */
			ret=ssl3_get_cert_verify(s);
			if (ret <= 0) goto end;
				s->state=SSL3_ST_SR_FINISHED_A;
			s->init_num=0;
			break;

		case SSL3_ST_SR_FINISHED_A:
		case SSL3_ST_SR_FINISHED_B:
			s->d1->change_cipher_spec_ok = 1;
			ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A,
				SSL3_ST_SR_FINISHED_B);
			if (ret <= 0) goto end;
			dtls1_stop_timer(s);
			if (s->hit)
				s->state=SSL_ST_OK;
			else if (s->tlsext_ticket_expected)
				s->state=SSL3_ST_SW_SESSION_TICKET_A;
			else
				s->state=SSL3_ST_SW_CHANGE_A;
			s->init_num=0;
			break;

		case SSL3_ST_SW_SESSION_TICKET_A:
		case SSL3_ST_SW_SESSION_TICKET_B:
			ret=ssl3_send_newsession_ticket(s);
			if (ret <= 0) goto end;
			s->state=SSL3_ST_SW_CHANGE_A;
			s->init_num=0;
			break;

		case SSL3_ST_SW_CERT_STATUS_A:
		case SSL3_ST_SW_CERT_STATUS_B:
			ret=ssl3_send_cert_status(s);
			if (ret <= 0) goto end;
			s->state=SSL3_ST_SW_KEY_EXCH_A;
			s->init_num=0;
			break;


		case SSL3_ST_SW_CHANGE_A:
		case SSL3_ST_SW_CHANGE_B:

			s->session->cipher=s->s3->tmp.new_cipher;
			if (!s->method->ssl3_enc->setup_key_block(s))
				{ ret= -1; goto end; }

			ret=dtls1_send_change_cipher_spec(s,
				SSL3_ST_SW_CHANGE_A,SSL3_ST_SW_CHANGE_B);

			if (ret <= 0) goto end;

			s->state=SSL3_ST_SW_FINISHED_A;
			s->init_num=0;

			if (!s->method->ssl3_enc->change_cipher_state(s,
				SSL3_CHANGE_CIPHER_SERVER_WRITE))
				{
				ret= -1;
				goto end;
				}

			dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
			break;

		case SSL3_ST_SW_FINISHED_A:
		case SSL3_ST_SW_FINISHED_B:
			ret=ssl3_send_finished(s,
				SSL3_ST_SW_FINISHED_A,SSL3_ST_SW_FINISHED_B,
				s->method->ssl3_enc->server_finished_label,
				s->method->ssl3_enc->server_finished_label_len);
			if (ret <= 0) goto end;
			s->state=SSL3_ST_SW_FLUSH;
			if (s->hit)
				{
				s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
				}
			else
				{
				s->s3->tmp.next_state=SSL_ST_OK;
				}
			s->init_num=0;
			break;

		case SSL_ST_OK:
			/* clean a few things up */
			ssl3_cleanup_key_block(s);

#if 0
			BUF_MEM_free(s->init_buf);
			s->init_buf=NULL;
#endif

			/* remove buffering on output */
			ssl_free_wbio_buffer(s);

			s->init_num=0;

			if (s->renegotiate == 2) /* skipped if we just sent a HelloRequest */
				{
				s->renegotiate=0;
				s->new_session=0;
				
				ssl_update_cache(s,SSL_SESS_CACHE_SERVER);
				
				s->ctx->stats.sess_accept_good++;
				/* s->server=1; */
				s->handshake_func=dtls1_accept;

				if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1);
				}
			
			ret = 1;

			/* done handshaking, next message is client hello */
			s->d1->handshake_read_seq = 0;
			/* next message is server hello */
			s->d1->handshake_write_seq = 0;
			s->d1->next_handshake_write_seq = 0;
			goto end;
			/* break; */

		default:
			OPENSSL_PUT_ERROR(SSL, dtls1_accept, SSL_R_UNKNOWN_STATE);
			ret= -1;
			goto end;
			/* break; */
			}
		
		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_ACCEPT_LOOP,1);
				s->state=new_state;
				}
			}
		skip=0;
		}
end:
	/* BIO_flush(s->wbio); */

	s->in_handshake--;

	if (cb != NULL)
		cb(s,SSL_CB_ACCEPT_EXIT,ret);
	return(ret);
	}
示例#27
0
int ssl2_connect(SSL *s)
	{
	unsigned long l=(unsigned long)time(NULL);
	BUF_MEM *buf=NULL;
	int ret= -1;
	void (*cb)(const SSL *ssl,int type,int val)=NULL;
	int new_state,state;

	RAND_add(&l,sizeof(l),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;

	/* init things to blank */
	s->in_handshake++;
	if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);

	for (;;)
		{
		state=s->state;

		switch (s->state)
			{
		case SSL_ST_BEFORE:
		case SSL_ST_CONNECT:
		case SSL_ST_BEFORE|SSL_ST_CONNECT:
		case SSL_ST_OK|SSL_ST_CONNECT:

			s->server=0;
			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);

			s->version=SSL2_VERSION;
			s->type=SSL_ST_CONNECT;

			buf=s->init_buf;
			if ((buf == NULL) && ((buf=BUF_MEM_new()) == NULL))
				{
				ret= -1;
				goto end;
				}
			if (!BUF_MEM_grow(buf,
				SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER))
				{
				if (buf == s->init_buf)
					buf=NULL;
				ret= -1;
				goto end;
				}
			s->init_buf=buf;
			buf=NULL;
			s->init_num=0;
			s->state=SSL2_ST_SEND_CLIENT_HELLO_A;
			s->ctx->stats.sess_connect++;
			s->handshake_func=ssl2_connect;
			BREAK;

		case SSL2_ST_SEND_CLIENT_HELLO_A:
		case SSL2_ST_SEND_CLIENT_HELLO_B:
			s->shutdown=0;
			ret=client_hello(s);
			if (ret <= 0) goto end;
			s->init_num=0;
			s->state=SSL2_ST_GET_SERVER_HELLO_A;
			BREAK;
		
		case SSL2_ST_GET_SERVER_HELLO_A:
		case SSL2_ST_GET_SERVER_HELLO_B:
			ret=get_server_hello(s);
			if (ret <= 0) goto end;
			s->init_num=0;
			if (!s->hit) /* new session */
				{
				s->state=SSL2_ST_SEND_CLIENT_MASTER_KEY_A;
				BREAK; 
				}
			else
				{
				s->state=SSL2_ST_CLIENT_START_ENCRYPTION;
				break;
				}
	
		case SSL2_ST_SEND_CLIENT_MASTER_KEY_A:
		case SSL2_ST_SEND_CLIENT_MASTER_KEY_B:
			ret=client_master_key(s);
			if (ret <= 0) goto end;
			s->init_num=0;
			s->state=SSL2_ST_CLIENT_START_ENCRYPTION;
			break;

		case SSL2_ST_CLIENT_START_ENCRYPTION:
			/* Ok, we now have all the stuff needed to
			 * start encrypting, so lets fire it up :-) */
			if (!ssl2_enc_init(s,1))
				{
				ret= -1;
				goto end;
				}
			s->s2->clear_text=0;
			s->state=SSL2_ST_SEND_CLIENT_FINISHED_A;
			break;

		case SSL2_ST_SEND_CLIENT_FINISHED_A:
		case SSL2_ST_SEND_CLIENT_FINISHED_B:
			ret=client_finished(s);
			if (ret <= 0) goto end;
			s->init_num=0;
			s->state=SSL2_ST_GET_SERVER_VERIFY_A;
			break;

		case SSL2_ST_GET_SERVER_VERIFY_A:
		case SSL2_ST_GET_SERVER_VERIFY_B:
			ret=get_server_verify(s);
			if (ret <= 0) goto end;
			s->init_num=0;
			s->state=SSL2_ST_GET_SERVER_FINISHED_A;
			break;

		case SSL2_ST_GET_SERVER_FINISHED_A:
		case SSL2_ST_GET_SERVER_FINISHED_B:
			ret=get_server_finished(s);
			if (ret <= 0) goto end;
			break;

		case SSL2_ST_SEND_CLIENT_CERTIFICATE_A:
		case SSL2_ST_SEND_CLIENT_CERTIFICATE_B:
		case SSL2_ST_SEND_CLIENT_CERTIFICATE_C:
		case SSL2_ST_SEND_CLIENT_CERTIFICATE_D:
		case SSL2_ST_X509_GET_CLIENT_CERTIFICATE:
			ret=client_certificate(s);
			if (ret <= 0) goto end;
			s->init_num=0;
			s->state=SSL2_ST_GET_SERVER_FINISHED_A;
			break;

		case SSL_ST_OK:
			if (s->init_buf != NULL)
				{
				BUF_MEM_free(s->init_buf);
				s->init_buf=NULL;
				}
			s->init_num=0;
		/*	ERR_clear_error();*/

			/* If we want to cache session-ids in the client
			 * and we successfully add the session-id to the
			 * cache, and there is a callback, then pass it out.
			 * 26/11/96 - eay - only add if not a re-used session.
			 */

			ssl_update_cache(s,SSL_SESS_CACHE_CLIENT);
			if (s->hit) s->ctx->stats.sess_hit++;

			ret=1;
			/* s->server=0; */
			s->ctx->stats.sess_connect_good++;

			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1);

			goto end;
			/* break; */
		default:
			SSLerr(SSL_F_SSL2_CONNECT,SSL_R_UNKNOWN_STATE);
			return(-1);
			/* break; */
			}

		if ((cb != NULL) && (s->state != state))
			{
			new_state=s->state;
			s->state=state;
			cb(s,SSL_CB_CONNECT_LOOP,1);
			s->state=new_state;
			}
		}
end:
	s->in_handshake--;
	if (buf != NULL)
		BUF_MEM_free(buf);
	if (cb != NULL) 
		cb(s,SSL_CB_CONNECT_EXIT,ret);
	return(ret);
	}
示例#28
0
int dtls1_accept(SSL *s)
{
    void (*cb)(const SSL *ssl, int type, int val) = NULL;
    unsigned long alg_k;
    int ret = -1;
    int new_state, state, skip = 0;
    int listen;

    ERR_clear_error();
    errno = 0;

    if (s->info_callback != NULL)
        cb = s->info_callback;
    else if (s->ctx->info_callback != NULL)
        cb = s->ctx->info_callback;

    listen = s->d1->listen;

    /* init things to blank */
    s->in_handshake++;
    if (!SSL_in_init(s) || SSL_in_before(s))
        SSL_clear(s);

    s->d1->listen = listen;

    if (s->cert == NULL) {
        SSLerr(SSL_F_DTLS1_ACCEPT, SSL_R_NO_CERTIFICATE_SET);
        return (-1);
    }

    for (;;) {
        state = s->state;

        switch (s->state) {
            case SSL_ST_RENEGOTIATE:
                s->renegotiate = 1;
            /* s->state=SSL_ST_ACCEPT; */

            case SSL_ST_BEFORE:
            case SSL_ST_ACCEPT:
            case SSL_ST_BEFORE | SSL_ST_ACCEPT:
            case SSL_ST_OK | SSL_ST_ACCEPT:

                s->server = 1;
                if (cb != NULL)
                    cb(s, SSL_CB_HANDSHAKE_START, 1);

                if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00)) {
                    SSLerr(SSL_F_DTLS1_ACCEPT, ERR_R_INTERNAL_ERROR);
                    return -1;
                }
                s->type = SSL_ST_ACCEPT;

                if (s->init_buf == NULL) {
                    BUF_MEM *buf;
                    if ((buf = BUF_MEM_new()) == NULL) {
                        ret = -1;
                        s->state = SSL_ST_ERR;
                        goto end;
                    }
                    if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
                        BUF_MEM_free(buf);
                        ret = -1;
                        s->state = SSL_ST_ERR;
                        goto end;
                    }
                    s->init_buf = buf;
                }

                if (!ssl3_setup_buffers(s)) {
                    ret = -1;
                    s->state = SSL_ST_ERR;
                    goto end;
                }

                s->init_num = 0;
                s->d1->change_cipher_spec_ok = 0;
                /* Should have been reset by ssl3_get_finished, too. */
                s->s3->change_cipher_spec = 0;

                if (s->state != SSL_ST_RENEGOTIATE) {
                    /*
                     * Ok, we now need to push on a buffering BIO so that
                     * the output is sent in a way that TCP likes :-)
                     * ...but not with SCTP :-)
                     */
                    if (!ssl_init_wbio_buffer(s, 1)) {
                        ret = -1;
                        s->state = SSL_ST_ERR;
                        goto end;
                    }

                    tls1_init_finished_mac(s);
                    s->state = SSL3_ST_SR_CLNT_HELLO_A;
                    s->ctx->stats.sess_accept++;
                } else if (!s->s3->send_connection_binding) {
                    /*
                     * Server attempting to renegotiate with client that doesn't
                     * support secure renegotiation.
                     */
                    SSLerr(SSL_F_DTLS1_ACCEPT,
                           SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
                    ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
                    ret = -1;
                    s->state = SSL_ST_ERR;
                    goto end;
                } else {
                    /* s->state == SSL_ST_RENEGOTIATE,
                     * we will just send a HelloRequest */
                    s->ctx->stats.sess_accept_renegotiate++;
                    s->state = SSL3_ST_SW_HELLO_REQ_A;
                }

                break;

            case SSL3_ST_SW_HELLO_REQ_A:
            case SSL3_ST_SW_HELLO_REQ_B:

                s->shutdown = 0;
                dtls1_clear_sent_buffer(s);
                dtls1_start_timer(s);
                ret = ssl3_send_hello_request(s);
                if (ret <= 0)
                    goto end;
                s->s3->tmp.next_state = SSL3_ST_SR_CLNT_HELLO_A;
                s->state = SSL3_ST_SW_FLUSH;
                s->init_num = 0;

                tls1_init_finished_mac(s);
                break;

            case SSL3_ST_SW_HELLO_REQ_C:
                s->state = SSL_ST_OK;
                break;

            case SSL3_ST_SR_CLNT_HELLO_A:
            case SSL3_ST_SR_CLNT_HELLO_B:
            case SSL3_ST_SR_CLNT_HELLO_C:

                s->shutdown = 0;
                ret = ssl3_get_client_hello(s);
                if (ret <= 0)
                    goto end;
                dtls1_stop_timer(s);

                if (ret == 1 && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE))
                    s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A;
                else
                    s->state = SSL3_ST_SW_SRVR_HELLO_A;

                s->init_num = 0;

                /* Reflect ClientHello sequence to remain stateless while listening */
                if (listen) {
                    memcpy(s->s3->write_sequence, s->s3->read_sequence,
                           sizeof(s->s3->write_sequence));
                }

                /* If we're just listening, stop here */
                if (listen && s->state == SSL3_ST_SW_SRVR_HELLO_A) {
                    ret = 2;
                    s->d1->listen = 0;
                    /*
                     * Set expected sequence numbers
                     * to continue the handshake.
                     */
                    s->d1->handshake_read_seq = 2;
                    s->d1->handshake_write_seq = 1;
                    s->d1->next_handshake_write_seq = 1;
                    goto end;
                }

                break;

            case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A:
            case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B:

                ret = dtls1_send_hello_verify_request(s);
                if (ret <= 0)
                    goto end;
                s->state = SSL3_ST_SW_FLUSH;
                s->s3->tmp.next_state = SSL3_ST_SR_CLNT_HELLO_A;

                /* HelloVerifyRequest resets Finished MAC */
                tls1_init_finished_mac(s);
                break;


            case SSL3_ST_SW_SRVR_HELLO_A:
            case SSL3_ST_SW_SRVR_HELLO_B:
                s->renegotiate = 2;
                dtls1_start_timer(s);
                ret = ssl3_send_server_hello(s);
                if (ret <= 0)
                    goto end;

                if (s->hit) {
                    if (s->tlsext_ticket_expected)
                        s->state = SSL3_ST_SW_SESSION_TICKET_A;
                    else
                        s->state = SSL3_ST_SW_CHANGE_A;
                } else
                    s->state = SSL3_ST_SW_CERT_A;
                s->init_num = 0;
                break;

            case SSL3_ST_SW_CERT_A:
            case SSL3_ST_SW_CERT_B:
                /* Check if it is anon DH. */
                if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)) {
                    dtls1_start_timer(s);
                    ret = ssl3_send_server_certificate(s);
                    if (ret <= 0)
                        goto end;
                    if (s->tlsext_status_expected)
                        s->state = SSL3_ST_SW_CERT_STATUS_A;
                    else
                        s->state = SSL3_ST_SW_KEY_EXCH_A;
                } else {
                    skip = 1;
                    s->state = SSL3_ST_SW_KEY_EXCH_A;
                }
                s->init_num = 0;
                break;

            case SSL3_ST_SW_KEY_EXCH_A:
            case SSL3_ST_SW_KEY_EXCH_B:
                alg_k = s->s3->tmp.new_cipher->algorithm_mkey;

                /* only send if a DH key exchange */
                if (alg_k & (SSL_kDHE | SSL_kECDHE)) {
                    dtls1_start_timer(s);
                    ret = ssl3_send_server_key_exchange(s);
                    if (ret <= 0)
                        goto end;
                } else
                    skip = 1;

                s->state = SSL3_ST_SW_CERT_REQ_A;
                s->init_num = 0;
                break;

            case SSL3_ST_SW_CERT_REQ_A:
            case SSL3_ST_SW_CERT_REQ_B:
                /*
                 * Determine whether or not we need to request a
                 * certificate.
                 *
                 * Do not request a certificate if:
                 *
                 * - We did not ask for it (SSL_VERIFY_PEER is unset).
                 *
                 * - SSL_VERIFY_CLIENT_ONCE is set and we are
                 *   renegotiating.
                 *
                 * - We are using an anonymous ciphersuites
                 *   (see section "Certificate request" in SSL 3 drafts
                 *   and in RFC 2246) ... except when the application
                 *   insists on verification (against the specs, but
                 *   s3_clnt.c accepts this for SSL 3).
                 */
                if (!(s->verify_mode & SSL_VERIFY_PEER) ||
                    ((s->session->peer != NULL) &&
                    (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) ||
                    ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
                    !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)))
                {
                    /* no cert request */
                    skip = 1;
                    s->s3->tmp.cert_request = 0;
                    s->state = SSL3_ST_SW_SRVR_DONE_A;
                } else {
                    s->s3->tmp.cert_request = 1;
                    dtls1_start_timer(s);
                    ret = ssl3_send_certificate_request(s);
                    if (ret <= 0)
                        goto end;
                    s->state = SSL3_ST_SW_SRVR_DONE_A;
                    s->init_num = 0;
                }
                break;

            case SSL3_ST_SW_SRVR_DONE_A:
            case SSL3_ST_SW_SRVR_DONE_B:
                dtls1_start_timer(s);
                ret = ssl3_send_server_done(s);
                if (ret <= 0)
                    goto end;
                s->s3->tmp.next_state = SSL3_ST_SR_CERT_A;
                s->state = SSL3_ST_SW_FLUSH;
                s->init_num = 0;
                break;

            case SSL3_ST_SW_FLUSH:
                s->rwstate = SSL_WRITING;
                if (BIO_flush(s->wbio) <= 0) {
                    /* If the write error was fatal, stop trying */
                    if (!BIO_should_retry(s->wbio)) {
                        s->rwstate = SSL_NOTHING;
                        s->state = s->s3->tmp.next_state;
                    }

                    ret = -1;
                    goto end;
                }
                s->rwstate = SSL_NOTHING;
                s->state = s->s3->tmp.next_state;
                break;

            case SSL3_ST_SR_CERT_A:
            case SSL3_ST_SR_CERT_B:
                if (s->s3->tmp.cert_request) {
                    ret = ssl3_get_client_certificate(s);
                    if (ret <= 0)
                        goto end;
                }
                s->init_num = 0;
                s->state = SSL3_ST_SR_KEY_EXCH_A;
                break;

            case SSL3_ST_SR_KEY_EXCH_A:
            case SSL3_ST_SR_KEY_EXCH_B:
                ret = ssl3_get_client_key_exchange(s);
                if (ret <= 0)
                    goto end;

                s->state = SSL3_ST_SR_CERT_VRFY_A;
                s->init_num = 0;

                if (ret == 2) {
                    /* For the ECDH ciphersuites when
                     * the client sends its ECDH pub key in
                     * a certificate, the CertificateVerify
                     * message is not sent.
                     */
                    s->state = SSL3_ST_SR_FINISHED_A;
                    s->init_num = 0;
                } else if (SSL_USE_SIGALGS(s)) {
                    s->state = SSL3_ST_SR_CERT_VRFY_A;
                    s->init_num = 0;
                    if (!s->session->peer)
                        break;
                    /*
                     * For sigalgs freeze the handshake buffer
                     * at this point and digest cached records.
                     */
                    if (!s->s3->handshake_buffer) {
                        SSLerr(SSL_F_DTLS1_ACCEPT, ERR_R_INTERNAL_ERROR);
                        s->state = SSL_ST_ERR;
                        return -1;
                    }
                    s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE;
                    if (!tls1_digest_cached_records(s)) {
                        s->state = SSL_ST_ERR;
                        return -1;
                    }
                } else {
                    s->state = SSL3_ST_SR_CERT_VRFY_A;
                    s->init_num = 0;

                    /* We need to get hashes here so if there is
                     * a client cert, it can be verified */
                    s->method->ssl3_enc->cert_verify_mac(s, NID_md5,
                                                         &(s->s3->tmp.cert_verify_md[0]));
                    s->method->ssl3_enc->cert_verify_mac(
                        s, NID_sha1, &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]));
                }
                break;

            case SSL3_ST_SR_CERT_VRFY_A:
            case SSL3_ST_SR_CERT_VRFY_B:
                ret = ssl3_get_cert_verify(s);
                if (ret <= 0)
                    goto end;
                s->state = SSL3_ST_SR_FINISHED_A;
                s->init_num = 0;
                break;

            case SSL3_ST_SR_FINISHED_A:
            case SSL3_ST_SR_FINISHED_B:
                /*
                 * Enable CCS. Receiving a CCS clears the flag, so make
                 * sure not to re-enable it to ban duplicates. This *should* be the
                 * first time we have received one - but we check anyway to be
                 * cautious.
                 * s->s3->change_cipher_spec is set when a CCS is
                 * processed in d1_pkt.c, and remains set until
                 * the client's Finished message is read.
                 */
                if (!s->s3->change_cipher_spec)
                    s->d1->change_cipher_spec_ok = 1;
                ret = ssl3_get_finished(s, SSL3_ST_SR_FINISHED_A, SSL3_ST_SR_FINISHED_B);
                if (ret <= 0)
                    goto end;
                dtls1_stop_timer(s);
                if (s->hit)
                    s->state = SSL_ST_OK;
                else if (s->tlsext_ticket_expected)
                    s->state = SSL3_ST_SW_SESSION_TICKET_A;
                else
                    s->state = SSL3_ST_SW_CHANGE_A;
                s->init_num = 0;
                break;

            case SSL3_ST_SW_SESSION_TICKET_A:
            case SSL3_ST_SW_SESSION_TICKET_B:
                ret = ssl3_send_newsession_ticket(s);
                if (ret <= 0)
                    goto end;
                s->state = SSL3_ST_SW_CHANGE_A;
                s->init_num = 0;
                break;

            case SSL3_ST_SW_CERT_STATUS_A:
            case SSL3_ST_SW_CERT_STATUS_B:
                ret = ssl3_send_cert_status(s);
                if (ret <= 0)
                    goto end;
                s->state = SSL3_ST_SW_KEY_EXCH_A;
                s->init_num = 0;
                break;

            case SSL3_ST_SW_CHANGE_A:
            case SSL3_ST_SW_CHANGE_B:

                s->session->cipher = s->s3->tmp.new_cipher;
                if (!s->method->ssl3_enc->setup_key_block(s)) {
                    ret = -1;
                    s->state = SSL_ST_ERR;
                    goto end;
                }

                ret = dtls1_send_change_cipher_spec(s, SSL3_ST_SW_CHANGE_A,
                                                    SSL3_ST_SW_CHANGE_B);

                if (ret <= 0)
                    goto end;


                s->state = SSL3_ST_SW_FINISHED_A;
                s->init_num = 0;

                if (!s->method->ssl3_enc->change_cipher_state(s,
                        SSL3_CHANGE_CIPHER_SERVER_WRITE))
                {
                    ret = -1;
                    s->state = SSL_ST_ERR;
                    goto end;
                }

                dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
                break;

            case SSL3_ST_SW_FINISHED_A:
            case SSL3_ST_SW_FINISHED_B:
                ret = ssl3_send_finished(s, SSL3_ST_SW_FINISHED_A, SSL3_ST_SW_FINISHED_B,
                                         s->method->ssl3_enc->server_finished_label,
                                         s->method->ssl3_enc->server_finished_label_len);
                if (ret <= 0)
                    goto end;
                s->state = SSL3_ST_SW_FLUSH;
                if (s->hit) {
                    s->s3->tmp.next_state = SSL3_ST_SR_FINISHED_A;

                } else {
                    s->s3->tmp.next_state = SSL_ST_OK;
                }
                s->init_num = 0;
                break;

            case SSL_ST_OK:
                /* clean a few things up */
                ssl3_cleanup_key_block(s);

                /* remove buffering on output */
                ssl_free_wbio_buffer(s);

                s->init_num = 0;

                if (s->renegotiate == 2) /* skipped if we just sent a HelloRequest */
                {
                    s->renegotiate = 0;
                    s->new_session = 0;

                    ssl_update_cache(s, SSL_SESS_CACHE_SERVER);

                    s->ctx->stats.sess_accept_good++;
                    /* s->server=1; */
                    s->handshake_func = dtls1_accept;

                    if (cb != NULL)
                        cb(s, SSL_CB_HANDSHAKE_DONE, 1);
                }

                ret = 1;

                /* done handshaking, next message is client hello */
                s->d1->handshake_read_seq = 0;
                /* next message is server hello */
                s->d1->handshake_write_seq = 0;
                s->d1->next_handshake_write_seq = 0;
                dtls1_clear_received_buffer(s);
                goto end;
            /* break; */

            case SSL_ST_ERR:
            default:
                SSLerr(SSL_F_DTLS1_ACCEPT, SSL_R_UNKNOWN_STATE);
                ret = -1;
                goto end;
                /* break; */
        }

        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_ACCEPT_LOOP, 1);
                s->state = new_state;
            }
        }
        skip = 0;
    }
end:
    /* BIO_flush(s->wbio); */

    s->in_handshake--;

    if (cb != NULL)
        cb(s, SSL_CB_ACCEPT_EXIT, ret);
    return ret;
}