コード例 #1
0
static int conn_state(BIO *b, BIO_CONNECT *c)
	{
	int ret= -1,i;
	unsigned long l;
	char *p,*q;
	int (*cb)(const BIO *,int,int)=NULL;

	if (c->info_callback != NULL)
		cb=c->info_callback;

	for (;;)
		{
		switch (c->state)
			{
		case BIO_CONN_S_BEFORE:
			p=c->param_hostname;
			if (p == NULL)
				{
				BIOerr(BIO_F_CONN_STATE,BIO_R_NO_HOSTNAME_SPECIFIED);
				goto exit_loop;
				}
			for ( ; *p != '\0'; p++)
				{
				if ((*p == ':') || (*p == '/')) break;
				}

			i= *p;
			if ((i == ':') || (i == '/'))
				{

				*(p++)='\0';
				if (i == ':')
					{
					for (q=p; *q; q++)
						if (*q == '/')
							{
							*q='\0';
							break;
							}
					if (c->param_port != NULL)
						OPENSSL_free(c->param_port);
					c->param_port=BUF_strdup(p);
					}
				}

			if (c->param_port == NULL)
				{
				BIOerr(BIO_F_CONN_STATE,BIO_R_NO_PORT_SPECIFIED);
				ERR_add_error_data(2,"host=",c->param_hostname);
				goto exit_loop;
				}
			c->state=BIO_CONN_S_GET_IP;
			break;

		case BIO_CONN_S_GET_IP:
			if (BIO_get_host_ip(c->param_hostname,&(c->ip[0])) <= 0)
				goto exit_loop;
			c->state=BIO_CONN_S_GET_PORT;
			break;

		case BIO_CONN_S_GET_PORT:
			if (c->param_port == NULL)
				{
				/* abort(); */
				goto exit_loop;
				}
			else if (BIO_get_port(c->param_port,&c->port) <= 0)
				goto exit_loop;
			c->state=BIO_CONN_S_CREATE_SOCKET;
			break;

		case BIO_CONN_S_CREATE_SOCKET:
			/* now setup address */
			TINYCLR_SSL_MEMSET((char *)&c->them,0,sizeof(c->them));
			c->them.sin_family=AF_INET;
			c->them.sin_port=TINYCLR_SSL_HTONS((unsigned short)c->port);
			l=(unsigned long)
				((unsigned long)c->ip[0]<<24L)|
				((unsigned long)c->ip[1]<<16L)|
				((unsigned long)c->ip[2]<< 8L)|
				((unsigned long)c->ip[3]);
			c->them.sin_addr.S_un.S_addr=TINYCLR_SSL_HTONL(l);
			c->state=BIO_CONN_S_CREATE_SOCKET;

			ret=TINYCLR_SSL_SOCKET(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
			if (ret == INVALID_SOCKET)
				{
				SYSerr(SYS_F_SOCKET,get_last_socket_error());
				ERR_add_error_data(4,"host=",c->param_hostname,
					":",c->param_port);
				BIOerr(BIO_F_CONN_STATE,BIO_R_UNABLE_TO_CREATE_SOCKET);
				goto exit_loop;
				}
			b->num=ret;
			c->state=BIO_CONN_S_NBIO;
			break;

		case BIO_CONN_S_NBIO:
			if (c->nbio)
				{
				if (!BIO_socket_nbio(b->num,1))
					{
					BIOerr(BIO_F_CONN_STATE,BIO_R_ERROR_SETTING_NBIO);
					ERR_add_error_data(4,"host=",
						c->param_hostname,
						":",c->param_port);
					goto exit_loop;
					}
				}
			c->state=BIO_CONN_S_CONNECT;

#if defined(SO_KEEPALIVE) && !defined(OPENSSL_SYS_MPE)
			i=1;
			i=TINYCLR_SSL_SETSOCKOPT(b->num,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
			if (i < 0)
				{
				SYSerr(SYS_F_SOCKET,get_last_socket_error());
				ERR_add_error_data(4,"host=",c->param_hostname,
					":",c->param_port);
				BIOerr(BIO_F_CONN_STATE,BIO_R_KEEPALIVE);
				goto exit_loop;
				}
#endif
			break;

		case BIO_CONN_S_CONNECT:
			BIO_clear_retry_flags(b);
			ret=TINYCLR_SSL_CONNECT(b->num,
				(struct TINYCLR_SSL_SOCKADDR *)&c->them,
				sizeof(c->them));
			b->retry_reason=0;
			if (ret < 0)
				{
				if (BIO_sock_should_retry(ret))
					{
					BIO_set_retry_special(b);
					c->state=BIO_CONN_S_BLOCKED_CONNECT;
					b->retry_reason=BIO_RR_CONNECT;
					}
				else
					{
					SYSerr(SYS_F_CONNECT,get_last_socket_error());
					ERR_add_error_data(4,"host=",
						c->param_hostname,
						":",c->param_port);
					BIOerr(BIO_F_CONN_STATE,BIO_R_CONNECT_ERROR);
					}
				goto exit_loop;
				}
			else
				c->state=BIO_CONN_S_OK;
			break;

		case BIO_CONN_S_BLOCKED_CONNECT:
			i=BIO_sock_error(b->num);
			if (i)
				{
				BIO_clear_retry_flags(b);
				SYSerr(SYS_F_CONNECT,i);
				ERR_add_error_data(4,"host=",
					c->param_hostname,
					":",c->param_port);
				BIOerr(BIO_F_CONN_STATE,BIO_R_NBIO_CONNECT_ERROR);
				ret=0;
				goto exit_loop;
				}
			else
				c->state=BIO_CONN_S_OK;
			break;

		case BIO_CONN_S_OK:
			ret=1;
			goto exit_loop;
		default:
			/* TINYCLR_SSL_ABORT(); */
			goto exit_loop;
			}

		if (cb != NULL)
			{
			if (!(ret=cb((BIO *)b,c->state,ret)))
				goto end;
			}
		}

	/* Loop does not exit */
exit_loop:
	if (cb != NULL)
		ret=cb((BIO *)b,c->state,ret);
end:
	return(ret);
	}
コード例 #2
0
void Test_OpenSSL_ClientServerAuth()
{
    LCD_Clear();
    lcd_printf("Testing SSL Client/Server negotiations...\n");
	int err;
	int client_numbytes, server_numbytes;
	int listen_sd;
	int server_sd;
	int client_sd;
	struct TINYCLR_SSL_SOCKADDR_IN sa_serv;
	struct TINYCLR_SSL_SOCKADDR_IN sa_cli;
	size_t client_len;
	SSL_CTX* server_ctx = NULL;
	SSL*     server_ssl = NULL;
	X509*    server_cert = NULL;
	SSL_CTX* client_ctx = NULL;
	SSL*     client_ssl = NULL;
	X509*    client_cert = NULL;
	char*    str = NULL;
	char     client_buf [256];
	char	 server_buf [256];
	SSL_METHOD *server_meth = NULL;
	SSL_METHOD *client_meth = NULL;
	BIO *cert = NULL;
	X509 *x = NULL;
	EVP_PKEY *pkey = NULL;

	// SSL preliminaries. 
	// create client ssl
	client_meth = (SSL_METHOD*)SSLv3_client_method();
	client_ctx = SSL_CTX_new (client_meth);
	if (!client_ctx) goto cleanup;

	server_meth = (SSL_METHOD*)SSLv3_server_method();
	server_ctx = SSL_CTX_new (server_meth);
	if (!server_ctx) goto cleanup;

	
	if ((cert=BIO_new(BIO_s_mem())) == NULL)
	{
		TINYCLR_SSL_PRINTF("Unable to create new BIO");
		goto cleanup;
	}
	BIO_puts(cert,server_pem);
	x=PEM_read_bio_X509_AUX(cert, NULL, 0, NULL);
	
	pkey=PEM_read_bio_PrivateKey(cert,NULL,
		server_ctx->default_passwd_callback,server_ctx->default_passwd_callback_userdata);
	//if (SSL_CTX_use_certificate_file(server_ctx, CERTF, SSL_FILETYPE_PEM) <= 0) {
	if (SSL_CTX_use_certificate(server_ctx, x) <= 0) 
	{ 
		TINYCLR_SSL_PRINTF("Use certifcate chain file failed");
		goto cleanup;
	}
	if (SSL_CTX_use_PrivateKey(server_ctx, pkey) <= 0) 
	{
		TINYCLR_SSL_PRINTF("Unable to use Private Key");
		goto cleanup;
	}

	if (!SSL_CTX_check_private_key(server_ctx)) {
		TINYCLR_SSL_PRINTF("Private key does not match the certificate public key\n");
		goto cleanup;
	}

	//if (SSL_CTX_set_cipher_list(server_ctx, );

	// ----------------------------------------------- 
	// Prepare TCP socket for receiving connections

	listen_sd = TINYCLR_SSL_SOCKET (AF_INET, SOCK_STREAM, IPPROTO_TCP);   
	if (listen_sd < 0) goto cleanup;

	// set it to non-blocking
	int nonblock = 1;
	err = TINYCLR_SSL_IOCTL(listen_sd,SOCK_FIONBIO,&nonblock);
	if (err < 0)
	{
		int wsa = TINYCLR_SSL_GETLASTSOCKETERROR();
		TINYCLR_SSL_PRINTF("Nonblocking call failed for server: %d.\n", wsa);
		goto cleanup;
	}

	TINYCLR_SSL_MEMSET(&sa_serv, '\0', sizeof(sa_serv));
	sa_serv.sin_family      		= AF_INET;
	sa_serv.sin_addr.S_un.S_addr 	= inet_addr("127.0.0.1");
	sa_serv.sin_port        		= TINYCLR_SSL_HTONS (1111);          /* Server Port number */

	TINYCLR_SSL_PRINTF("Binding to %d...\n", TINYCLR_SSL_NTOHS(sa_serv.sin_port));
	err = TINYCLR_SSL_BIND(listen_sd, (struct TINYCLR_SSL_SOCKADDR*) &sa_serv,
	     sizeof (sa_serv));                   

	if (err < 0)
	{
		int wsa = TINYCLR_SSL_GETLASTSOCKETERROR();
		TINYCLR_SSL_PRINTF("Bind Socket error %d\n", wsa);
		goto cleanup;
	}

	TINYCLR_SSL_PRINTF("Listening...\n");
	/* Receive a TCP connection. */     
	err = TINYCLR_SSL_LISTEN (listen_sd, 5);                    
	if (err < 0) 
	{
		int wsa = TINYCLR_SSL_GETLASTSOCKETERROR();
		TINYCLR_SSL_PRINTF("Listen Socket error %d\n", wsa);
		goto cleanup;
	}

	// create a client socket
	client_sd = TINYCLR_SSL_SOCKET (AF_INET, SOCK_STREAM, IPPROTO_TCP);   
	if (client_sd < 0) goto cleanup;

	// set it to non-blocking
	err = TINYCLR_SSL_IOCTL(client_sd,SOCK_FIONBIO,&nonblock);
	if (err < 0)
	{
		int wsa = TINYCLR_SSL_GETLASTSOCKETERROR();
		TINYCLR_SSL_PRINTF("Nonblocking call failed for client: %d.\n", wsa);
		goto cleanup;
	}
	// Set up a tcp connection for client: Bind, Connect
	err == TINYCLR_SSL_CONNECT( client_sd, (const struct TINYCLR_SSL_SOCKADDR*)&sa_serv, sizeof(sa_serv));
	if (err < 0)
	{
		int wsa = TINYCLR_SSL_GETLASTSOCKETERROR();
		TINYCLR_SSL_PRINTF("Client connect failed with: %d.\n", wsa);
	}

	
	client_len = sizeof(sa_cli);
	char nodename[128] = "";
	char servname[128] = "";
	SOCK_addrinfo hints;
	SOCK_addrinfo *res = NULL;
	
	TINYCLR_SSL_MEMSET(&hints, '\0', sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

	SOCK_getaddrinfo(nodename,servname,&hints,&res);

	SOCK_addrinfo *ptr = NULL;
	for (ptr=res; ptr!=NULL; ptr=ptr->ai_next)
	{	
		struct sockaddr_in *ip = (struct sockaddr_in*) ptr->ai_addr;
		TINYCLR_SSL_PRINTF("Accepting connections on...%s:%d\n", 
			inet_ntoa(ip->sin_addr), 1111 );
	}

	int counter=0;
	do
	{
		server_sd = TINYCLR_SSL_ACCEPT (listen_sd, (struct TINYCLR_SSL_SOCKADDR*) &sa_cli, (int*)&client_len);
        Events_WaitForEvents(0,2000);
		TINYCLR_SSL_PRINTF("Accept again %d:%d\n", TINYCLR_SSL_GETLASTSOCKETERROR(), counter++);
	} while (server_sd == -1);
	
	TINYCLR_SSL_CLOSESOCKET (listen_sd);

	TINYCLR_SSL_PRINTF ("Connection from %lx, port %x\n",
	sa_cli.sin_addr.S_un.S_addr, sa_cli.sin_port);


	// connections are completed between server & client
	// now lets do the SSL negotiations
	// create server ssl
	server_ssl = SSL_new(server_ctx);
	if (server_ssl == NULL) goto cleanup;
	SSL_set_fd (server_ssl, server_sd);

	//Create server bio and set as non-blocking
	BIO* server_bio = BIO_new(BIO_s_socket());
	if (server_bio == NULL) goto cleanup;
	//CHK_NULL(bio);
	BIO_set_nbio(server_bio,1);
	BIO_set_fd(server_bio, server_sd, BIO_NOCLOSE);
	SSL_set_bio(server_ssl,server_bio,server_bio);

	// create client ssl & connect
	client_ssl = SSL_new(client_ctx);
	if (client_ssl == NULL) goto cleanup;
	SSL_set_fd(client_ssl, client_sd);

	//Create client bio and set as non-blocking
	BIO* client_bio = BIO_new(BIO_s_socket());
	if (client_bio == NULL) goto cleanup;
	BIO_set_nbio(client_bio,1);
	BIO_set_fd(client_bio, client_sd, BIO_NOCLOSE);
	SSL_set_bio(client_ssl,client_bio,client_bio);

	
	
	// loop until server accepts ssl client connect
	int ssl_err =0;
	do
	{
		err = SSL_connect(client_ssl);
		if (err <= 0) 
		{
			ssl_err = SSL_get_error(client_ssl,err);
			TINYCLR_SSL_PRINTF("SSL_Connect error: %d\n", ssl_err);
		}
        Events_WaitForEvents(0,1000);
		err = SSL_accept (server_ssl);
		if (err <= 0) 
		{
			ssl_err = SSL_get_error(server_ssl, err);
			TINYCLR_SSL_PRINTF("SSL_Accept error: %d\n", ssl_err);
		}
        Events_WaitForEvents(0,1000);
	} while (err != 1);

	//Get the cipher - opt
	TINYCLR_SSL_PRINTF("SSL connection using %s\n", SSL_get_cipher (server_ssl));

	//Get client's certificate (note: beware of dynamic allocation) - opt
	client_cert = SSL_get_peer_certificate (server_ssl);
	if (client_cert != NULL) 
	{
		TINYCLR_SSL_PRINTF("Client certificate:\n");

		str = X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0);
		if (str == NULL) goto cleanup;

		TINYCLR_SSL_PRINTF("subject: %s\n", str);
		OPENSSL_free (str);

		str = X509_NAME_oneline (X509_get_issuer_name  (client_cert), 0, 0);
		if (str == NULL) goto cleanup;
		TINYCLR_SSL_PRINTF("issuer: %s\n", str);
		OPENSSL_free (str);

		//We could do all sorts of certificate verification stuff here before
		//   deallocating the certificate.

		X509_free (client_cert);
	} 
	else
		TINYCLR_SSL_PRINTF("Client does not have certificate.\n");
	
	//Get server's certificate (note: beware of dynamic allocation) - opt
	server_cert = SSL_get_peer_certificate (client_ssl);
	if (server_cert != NULL) 
	{
		TINYCLR_SSL_PRINTF("Server certificate:\n");

		str = X509_NAME_oneline (X509_get_subject_name (server_cert), 0, 0);
		if (str == NULL) goto cleanup;

		TINYCLR_SSL_PRINTF("subject: %s\n", str);
		OPENSSL_free (str);

		str = X509_NAME_oneline (X509_get_issuer_name  (server_cert), 0, 0);
		if (str == NULL) goto cleanup;
		TINYCLR_SSL_PRINTF("issuer: %s\n", str);
		OPENSSL_free (str);

		/* We could do all sorts of certificate verification stuff here before
		   deallocating the certificate. */

		X509_free (server_cert);
	} 
	else
		TINYCLR_SSL_PRINTF("Server with no certificate?!?!?.\n");

	do
	{

		// DATA EXCHANGE - Receive message and send reply. 
		err = SSL_write(client_ssl,"Hello World!",TINYCLR_SSL_STRLEN("Hello World!"));
		if (err <= 0) ssl_err = SSL_get_error(client_ssl, err);
        Events_WaitForEvents(0,1000);
		server_numbytes= SSL_read (server_ssl, server_buf, sizeof(server_buf) - 1);                   
		if (server_numbytes <= 0) 
			ssl_err = SSL_get_error(server_ssl, server_numbytes);
		else
			server_buf[server_numbytes] = '\0';
        Events_WaitForEvents(0,1000);

		err = SSL_write (server_ssl, "I hear you.", TINYCLR_SSL_STRLEN("I hear you."));  
		if (err <= 0) ssl_err = SSL_get_error(server_ssl, err);
        Events_WaitForEvents(0,1000);

		client_numbytes= SSL_read(client_ssl, client_buf, sizeof(client_buf) -1);
		if (client_numbytes <= 0) 
			ssl_err = SSL_get_error(client_ssl, client_numbytes);
		else
			client_buf[client_numbytes] = '\0';
        Events_WaitForEvents(0,1000);
		
	} while (err <= 0);

	TINYCLR_SSL_PRINTF("Server got %d chars:'%s'\n", server_numbytes, server_buf);
	TINYCLR_SSL_PRINTF("Client go %d chars:'%s'\n", client_numbytes, client_buf);
	/* Clean up. */

	cleanup:
	if (pkey) EVP_PKEY_free(pkey);
	if (cert) BIO_free(cert);
	if (x) X509_free(x);
	TINYCLR_SSL_CLOSESOCKET(server_sd);
	if (server_ssl) SSL_shutdown(server_ssl);
	if (server_ssl) SSL_free (server_ssl);
	server_ssl = NULL;
	if (server_ctx) SSL_CTX_free(server_ctx);
	server_ctx = NULL;
	TINYCLR_SSL_CLOSESOCKET(client_sd);
	if (client_ssl) SSL_shutdown(client_ssl);
	if (client_ssl) SSL_free (client_ssl);
	client_ssl = NULL;
	if (client_ctx) SSL_CTX_free(client_ctx);
	client_ctx = NULL;
}
コード例 #3
0
static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
	{
	long ret=1;
	int *ip;
	struct TINYCLR_SSL_SOCKADDR *to = NULL;
	bio_dgram_data *data = NULL;
#if defined(IP_MTU_DISCOVER) || defined(IP_MTU)
	long sockopt_val = 0;
	unsigned int sockopt_len = 0;
#endif
#ifdef OPENSSL_SYS_LINUX
	socklen_t addr_len;
	union	{
		struct TINYCLR_SSL_SOCKADDR	sa;
		struct TINYCLR_SSL_SOCKADDR_IN s4;
#if OPENSSL_USE_IPV6
		struct sockaddr_in6 s6;
#endif
		} addr;
#endif

	data = (bio_dgram_data *)b->ptr;

	switch (cmd)
		{
	case BIO_CTRL_RESET:
		num=0;
	case BIO_C_FILE_SEEK:
		ret=0;
		break;
	case BIO_C_FILE_TELL:
	case BIO_CTRL_INFO:
		ret=0;
		break;
	case BIO_C_SET_FD:
		dgram_clear(b);
		b->num= *((int *)ptr);
		b->shutdown=(int)num;
		b->init=1;
		break;
	case BIO_C_GET_FD:
		if (b->init)
			{
			ip=(int *)ptr;
			if (ip != NULL) *ip=b->num;
			ret=b->num;
			}
		else
			ret= -1;
		break;
	case BIO_CTRL_GET_CLOSE:
		ret=b->shutdown;
		break;
	case BIO_CTRL_SET_CLOSE:
		b->shutdown=(int)num;
		break;
	case BIO_CTRL_PENDING:
	case BIO_CTRL_WPENDING:
		ret=0;
		break;
	case BIO_CTRL_DUP:
	case BIO_CTRL_FLUSH:
		ret=1;
		break;
	case BIO_CTRL_DGRAM_CONNECT:
		to = (struct TINYCLR_SSL_SOCKADDR *)ptr;
#if 0
		if (TINYCLR_SSL_CONNECT(b->num, to, sizeof(struct TINYCLR_SSL_SOCKADDR)) < 0)
			{ TINYCLR_SSL_PERROR("connect"); ret = 0; }
		else
			{
#endif
			switch (to->sa_family)
				{
				case AF_INET:
					TINYCLR_SSL_MEMCPY(&data->peer,to,sizeof(data->peer.sa_in));
					break;
#if OPENSSL_USE_IPV6
				case AF_INET6:
					TINYCLR_SSL_MEMCPY(&data->peer,to,sizeof(data->peer.sa_in6));
					break;
#endif
				default:
					TINYCLR_SSL_MEMCPY(&data->peer,to,sizeof(data->peer.sa));
					break;
				}
#if 0
			}
#endif
		break;
		/* (Linux)kernel sets DF bit on outgoing IP packets */
	case BIO_CTRL_DGRAM_MTU_DISCOVER:
#ifdef OPENSSL_SYS_LINUX
		addr_len = (socklen_t)sizeof(addr);
		TINYCLR_SSL_MEMSET((void *)&addr, 0, sizeof(addr));
		if (getsockname(b->num, &addr.sa, &addr_len) < 0)
			{
			ret = 0;
			break;
			}
		sockopt_len = sizeof(sockopt_val);
		switch (addr.sa.sa_family)
			{
		case AF_INET:
			sockopt_val = IP_PMTUDISC_DO;
			if ((ret = TINYCLR_SSL_SETSOCKOPT(b->num, IPPROTO_IP, IP_MTU_DISCOVER,
				&sockopt_val, sizeof(sockopt_val))) < 0)
				TINYCLR_SSL_PERROR("setsockopt");
			break;
#if OPENSSL_USE_IPV6 && defined(IPV6_MTU_DISCOVER)
		case AF_INET6:
			sockopt_val = IPV6_PMTUDISC_DO;
			if ((ret = TINYCLR_SSL_SETSOCKOPT(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER,
				&sockopt_val, sizeof(sockopt_val))) < 0)
				TINYCLR_SSL_PERROR("setsockopt");
			break;
#endif
		default:
			ret = -1;
			break;
			}
		ret = -1;
#else
		break;
#endif
	case BIO_CTRL_DGRAM_QUERY_MTU:
#ifdef OPENSSL_SYS_LINUX
		addr_len = (socklen_t)sizeof(addr);
		TINYCLR_SSL_MEMSET((void *)&addr, 0, sizeof(addr));
		if (getsockname(b->num, &addr.sa, &addr_len) < 0)
			{
			ret = 0;
			break;
			}
		sockopt_len = sizeof(sockopt_val);
		switch (addr.sa.sa_family)
			{
		case AF_INET:
			if ((ret = TINYCLR_SSL_GETSOCKOPT(b->num, IPPROTO_IP, IP_MTU, (void *)&sockopt_val,
				&sockopt_len)) < 0 || sockopt_val < 0)
				{
				ret = 0;
				}
			else
				{
				/* we assume that the transport protocol is UDP and no
				 * IP options are used.
				 */
				data->mtu = sockopt_val - 8 - 20;
				ret = data->mtu;
				}
			break;
#if OPENSSL_USE_IPV6 && defined(IPV6_MTU)
		case AF_INET6:
			if ((ret = TINYCLR_SSL_GETSOCKOPT(b->num, IPPROTO_IPV6, IPV6_MTU, (void *)&sockopt_val,
				&sockopt_len)) < 0 || sockopt_val < 0)
				{
				ret = 0;
				}
			else
				{
				/* we assume that the transport protocol is UDP and no
				 * IPV6 options are used.
				 */
				data->mtu = sockopt_val - 8 - 40;
				ret = data->mtu;
				}
			break;
#endif
		default:
			ret = 0;
			break;
			}
#else
		ret = 0;
#endif
		break;
	case BIO_CTRL_DGRAM_GET_MTU:
		return data->mtu;
		break;
	case BIO_CTRL_DGRAM_SET_MTU:
		data->mtu = num;
		ret = num;
		break;
	case BIO_CTRL_DGRAM_SET_CONNECTED:
		to = (struct TINYCLR_SSL_SOCKADDR *)ptr;

		if ( to != NULL)
			{
			data->connected = 1;
			switch (to->sa_family)
				{
				case AF_INET:
					TINYCLR_SSL_MEMCPY(&data->peer,to,sizeof(data->peer.sa_in));
					break;
#if OPENSSL_USE_IPV6
				case AF_INET6:
					TINYCLR_SSL_MEMCPY(&data->peer,to,sizeof(data->peer.sa_in6));
					break;
#endif
				default:
					TINYCLR_SSL_MEMCPY(&data->peer,to,sizeof(data->peer.sa));
					break;
				}
			}
		else
			{
			data->connected = 0;
			TINYCLR_SSL_MEMSET(&(data->peer), 0x00, sizeof(data->peer));
			}
		break;
	case BIO_CTRL_DGRAM_GET_PEER:
		switch (data->peer.sa.sa_family)
			{
			case AF_INET:
				ret=sizeof(data->peer.sa_in);
				break;
#if OPENSSL_USE_IPV6
			case AF_INET6:
				ret=sizeof(data->peer.sa_in6);
				break;
#endif
			default:
				ret=sizeof(data->peer.sa);
				break;
			}
		if (num==0 || num>ret)
			num=ret;
		TINYCLR_SSL_MEMCPY(ptr,&data->peer,(ret=num));
		break;
	case BIO_CTRL_DGRAM_SET_PEER:
		to = (struct TINYCLR_SSL_SOCKADDR *) ptr;
		switch (to->sa_family)
			{
			case AF_INET:
				TINYCLR_SSL_MEMCPY(&data->peer,to,sizeof(data->peer.sa_in));
				break;
#if OPENSSL_USE_IPV6
			case AF_INET6:
				TINYCLR_SSL_MEMCPY(&data->peer,to,sizeof(data->peer.sa_in6));
				break;
#endif
			default:
				TINYCLR_SSL_MEMCPY(&data->peer,to,sizeof(data->peer.sa));
				break;
			}
		break;
	case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
		TINYCLR_SSL_MEMCPY(&(data->next_timeout), ptr, sizeof(struct TINYCLR_SSL_TIMEVAL));
		break;
#if defined(SO_RCVTIMEO)
	case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT:
#ifdef OPENSSL_SYS_WINDOWS
		{
		struct TINYCLR_SSL_TIMEVAL *tv = (struct TINYCLR_SSL_TIMEVAL *)ptr;
		int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000;
		if (TINYCLR_SSL_SETSOCKOPT(b->num, SOL_SOCKET, SO_RCVTIMEO,
			(const char*)&timeout, sizeof(timeout)) < 0)
			{ TINYCLR_SSL_PERROR("setsockopt"); ret = -1; }
		}
#else
		if ( TINYCLR_SSL_SETSOCKOPT(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr,
			sizeof(struct TINYCLR_SSL_TIMEVAL)) < 0)
			{ TINYCLR_SSL_PERROR("setsockopt");	ret = -1; }
#endif
		break;
	case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT:
#ifdef OPENSSL_SYS_WINDOWS
		{
		int timeout, sz = sizeof(timeout);
		struct TINYCLR_SSL_TIMEVAL *tv = (struct TINYCLR_SSL_TIMEVAL *)ptr;
		if (TINYCLR_SSL_GETSOCKOPT(b->num, SOL_SOCKET, SO_RCVTIMEO,
			(char*)&timeout, &sz) < 0)
			{ TINYCLR_SSL_PERROR("getsockopt"); ret = -1; }
		else
			{
			tv->tv_sec = timeout / 1000;
			tv->tv_usec = (timeout % 1000) * 1000;
			ret = sizeof(*tv);
			}
		}
#elif defined(OPENSSL_SYS_ARM) || defined(OPENSSL_SYS_SH)
		if ( TINYCLR_SSL_GETSOCKOPT(b->num, SOL_SOCKET, SO_RCVTIMEO, 
			ptr, (u32_t *)&ret) < 0)
			{ TINYCLR_SSL_PERROR("getsockopt"); ret = -1; }
#else
		if ( TINYCLR_SSL_GETSOCKOPT(b->num, SOL_SOCKET, SO_RCVTIMEO, 
			ptr, (void *)&ret) < 0)
			{ TINYCLR_SSL_PERROR("getsockopt"); ret = -1; }
#endif
		break;
#endif
#if defined(SO_SNDTIMEO)
	case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT:
#ifdef OPENSSL_SYS_WINDOWS
		{
		struct TINYCLR_SSL_TIMEVAL *tv = (struct TINYCLR_SSL_TIMEVAL *)ptr;
		int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000;
		if (TINYCLR_SSL_SETSOCKOPT(b->num, SOL_SOCKET, SO_SNDTIMEO,
			(const char*)&timeout, sizeof(timeout)) < 0)
			{ TINYCLR_SSL_PERROR("setsockopt"); ret = -1; }
		}
#else
		if ( TINYCLR_SSL_SETSOCKOPT(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr,
			sizeof(struct TINYCLR_SSL_TIMEVAL)) < 0)
			{ TINYCLR_SSL_PERROR("setsockopt");	ret = -1; }
#endif
		break;
	case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT:
#ifdef OPENSSL_SYS_WINDOWS
		{
		int timeout, sz = sizeof(timeout);
		struct TINYCLR_SSL_TIMEVAL *tv = (struct TINYCLR_SSL_TIMEVAL *)ptr;
		if (TINYCLR_SSL_GETSOCKOPT(b->num, SOL_SOCKET, SO_SNDTIMEO,
			(char*)&timeout, &sz) < 0)
			{ TINYCLR_SSL_PERROR("getsockopt"); ret = -1; }
		else
			{
			tv->tv_sec = timeout / 1000;
			tv->tv_usec = (timeout % 1000) * 1000;
			ret = sizeof(*tv);
			}
		}
#elif defined(OPENSSL_SYS_ARM) || defined(OPENSSL_SYS_SH)
		if ( TINYCLR_SSL_GETSOCKOPT(b->num, SOL_SOCKET, SO_SNDTIMEO, 
			ptr, (u32_t *)&ret) < 0)
			{ TINYCLR_SSL_PERROR("getsockopt"); ret = -1; }
#else
		if ( TINYCLR_SSL_GETSOCKOPT(b->num, SOL_SOCKET, SO_SNDTIMEO, 
			ptr, (void *)&ret) < 0)
			{ TINYCLR_SSL_PERROR("getsockopt"); ret = -1; }
#endif
		break;
#endif
	case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP:
		/* fall-through */
	case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP:
#ifdef OPENSSL_SYS_WINDOWS
		if ( data->_errno == WSAETIMEDOUT)
#else
		if ( data->_errno == EAGAIN)
#endif
			{
			ret = 1;
			data->_errno = 0;
			}
		else
			ret = 0;
		break;
#ifdef EMSGSIZE
	case BIO_CTRL_DGRAM_MTU_EXCEEDED:
		if ( data->_errno == EMSGSIZE)
			{
			ret = 1;
			data->_errno = 0;
			}
		else
			ret = 0;
		break;
#endif
	default:
		ret=0;
		break;
		}
	return(ret);
	}