Attached is a patch to enable (SIEVE) STARTTLS support for fsockopen 
using stls://host.example.org
I'm pretty sure I've got it to conform to the RFC:
http://www.holtmann.org/email/sieve/draft-martin-managesieve-03.txt
Currently it only works with SIEVE, but it could be easily extended to 
do SMTP (Send "EHLO hostname" first) and IMAP.
Maybe something like sieve+stls:// and smtp+stls:// would be better 
for the separate STARTTLS setups.

http://am-productions.biz/docs/patch-openssl-starttls.patch

I'm sure there are a bunch of things "wrong" with how I've done this, 
so feel free to send suggestions.

Thanks,
-- 
Anish Mistry
diff -ruN ext/openssl/xp_ssl.c ext/openssl/xp_ssl.c
--- ext/openssl/xp_ssl.c	Wed Sep  7 11:36:23 2005
+++ ext/openssl/xp_ssl.c	Sun Dec 18 04:18:15 2005
@@ -31,8 +31,26 @@
 #include <sys/select.h>
 #endif
 
+#define STARTTLS_BUFFER 1024
+#define STARTTLS_CMD_CAPABILITY "CAPABILITY"
+#define STARTTLS_CMD_STARTTLS "STARTTLS"
+#define STARTTLS_CMD_LOGOUT "LOGOUT"
+#define STARTTLS_CAPABLE "\"STARTTLS\""
+#define STARTTLS_RESPONSE_OK "OK"
+#define STARTTLS_RESPONSE_BAD "BAD"
+#define STARTTLS_ENDLINE "\n"
+
+enum starttls_state {
+STARTTLS_STATE_CONNECT,
+STARTTLS_STATE_CAPABILITY,
+STARTTLS_STATE_HAS_CAPABILITY,
+STARTTLS_STATE_NEGOTIATE,
+STARTTLS_STATE_TERMINATE
+};
+
 int php_openssl_apply_verification_policy(SSL *ssl, X509 *peer, php_stream *stream TSRMLS_DC);
 SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream *stream TSRMLS_DC);
+int php_stream_starttls_setup(php_stream *stream);
 
 /* This implementation is very closely tied to the that of the native
  * sockets implemented in the core.
@@ -324,6 +342,10 @@
 			sslsock->is_client = 1;
 			method = TLSv1_client_method();
 			break;
+		case STREAM_CRYPTO_METHOD_STLS_CLIENT:
+			sslsock->is_client = 1;
+			method = TLSv1_client_method();
+			break;
 		case STREAM_CRYPTO_METHOD_SSLv23_SERVER:
 			sslsock->is_client = 0;
 			method = SSLv23_server_method();
@@ -435,7 +457,6 @@
 		php_stream_xport_param *xparam STREAMS_DC TSRMLS_DC)
 {
 	int clisock;
-
 	xparam->outputs.client = NULL;
 
 	clisock = php_network_accept_incoming(sock->s.socket,
@@ -484,6 +505,10 @@
 				case STREAM_CRYPTO_METHOD_TLS_CLIENT:
 					sock->method = STREAM_CRYPTO_METHOD_TLS_SERVER;
 					break;
+				case STREAM_CRYPTO_METHOD_STLS_CLIENT:
+					php_stream_starttls_setup(stream);
+					sock->method = STREAM_CRYPTO_METHOD_TLS_SERVER;
+					break;
 			}
 
 			clisockdata->method = sock->method;
@@ -704,12 +729,120 @@
 	} else if (strncmp(proto, "tls", protolen) == 0) {
 		sslsock->enable_on_connect = 1;
 		sslsock->method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
+	} else if (strncmp(proto, "stls", protolen) == 0) {
+		sslsock->enable_on_connect = 1;
+		sslsock->method = STREAM_CRYPTO_METHOD_STLS_CLIENT;
 	}
 
 	return stream;
 }
 
+int php_stream_starttls_setup(php_stream *stream)
+{
+	char buffer[STARTTLS_BUFFER];
+	char *curstring = NULL;
+	char *curtoken = NULL;
+	int conn_state = STARTTLS_STATE_CONNECT;
+	int bytesread = 0;
+	/* STLS/STARTTLS requires STARTTLS to be sent
+	and OK'd be the server before a TLS negotiation
+	may begin. */
+	while(conn_state != STARTTLS_STATE_NEGOTIATE && conn_state != STARTTLS_STATE_TERMINATE && php_stream_gets(stream,buffer,STARTTLS_BUFFER) != NULL && !php_stream_eof(stream))
+	{
+		switch(conn_state)
+		{
+			case STARTTLS_STATE_CONNECT:
+				curstring = buffer;
+				curtoken = buffer;
+			
+				curtoken = strsep(&curstring, " \t\n\r");
+				while(curstring != NULL)
+				{
+					if(strncmp(STARTTLS_RESPONSE_OK,buffer,sizeof(STARTTLS_RESPONSE_OK)) == 0)
+					{
+						conn_state = STARTTLS_STATE_CAPABILITY;
+						/* The server is ready for commands */
+						php_write_stream(stream,STARTTLS_CMD_CAPABILITY,sizeof(STARTTLS_CMD_CAPABILITY));
+						php_write_stream(stream,STARTTLS_ENDLINE,sizeof(STARTTLS_ENDLINE));
+						curstring = NULL;
+
+					}
+					else if(strncmp(STARTTLS_RESPONSE_BAD,buffer,sizeof(STARTTLS_RESPONSE_BAD)) == 0)
+					{
+						conn_state = STARTTLS_STATE_TERMINATE;
+						curstring = NULL;
+						break;
+
+					}
+					else
+						curtoken = strsep(&curstring, " \t\n\r");
+				}
+				break;
+			case STARTTLS_STATE_CAPABILITY:
+				curstring = buffer;
+				curtoken = buffer;
+			
+				curtoken = strsep(&curstring, " \t\n\r");
+				while(curstring != NULL)
+				{
+					if(strncmp(STARTTLS_CAPABLE,buffer,sizeof(STARTTLS_CAPABLE)) == 0)
+					{
+						conn_state = STARTTLS_STATE_HAS_CAPABILITY;
+						/* The server is ready for commands */
+						php_write_stream(stream,STARTTLS_CMD_CAPABILITY,sizeof(STARTTLS_CMD_CAPABILITY));
+						php_write_stream(stream,STARTTLS_ENDLINE,sizeof(STARTTLS_ENDLINE));
+						curstring = NULL;
 
+					}
+					else if(strncmp(STARTTLS_RESPONSE_BAD,buffer,sizeof(STARTTLS_RESPONSE_BAD)) == 0)
+					{
+						conn_state = STARTTLS_STATE_TERMINATE;
+						curstring = NULL;
+						break;
+
+					}
+					else
+						curtoken = strsep(&curstring, " \t\n\r");
+				}
+				break;
+			case STARTTLS_STATE_HAS_CAPABILITY:
+				curstring = buffer;
+				curtoken = buffer;
+			
+				curtoken = strsep(&curstring, " \t\n\r");
+				while(curstring != NULL)
+				{
+					if(strncmp(STARTTLS_RESPONSE_OK,buffer,sizeof(STARTTLS_RESPONSE_OK)) == 0)
+					{
+						conn_state = STARTTLS_STATE_NEGOTIATE;
+						/* The server is ready for commands */
+						php_write_stream(stream,STARTTLS_CMD_STARTTLS,sizeof(STARTTLS_CMD_STARTTLS));
+						php_write_stream(stream,STARTTLS_ENDLINE,sizeof(STARTTLS_ENDLINE));
+						curstring = NULL;
+
+					}
+					else if(strncmp(STARTTLS_RESPONSE_BAD,buffer,sizeof(STARTTLS_RESPONSE_BAD)) == 0)
+					{
+						conn_state = STARTTLS_STATE_TERMINATE;
+						curstring = NULL;
+						break;
+
+					}
+					else
+						curtoken = strsep(&curstring, " \t\n\r");
+				}
+				break;
+		}
+	}
+	if(conn_state == STARTTLS_STATE_TERMINATE)
+	{
+		php_write_stream(stream,STARTTLS_CMD_LOGOUT,sizeof(STARTTLS_CMD_LOGOUT));
+		php_write_stream(stream,STARTTLS_ENDLINE,sizeof(STARTTLS_ENDLINE));
+		return 0;
+	}
+	return 1;
+
+}
 
 /*
  * Local variables:
diff -ruN ext/standard/file.c ext/standard/file.c
--- ext/standard/file.c	Fri Oct 21 08:13:37 2005
+++ ext/standard/file.c	Sun Dec 18 04:18:14 2005
@@ -223,6 +223,7 @@
 	REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_SSLv3_CLIENT",		STREAM_CRYPTO_METHOD_SSLv3_CLIENT,	CONST_CS|CONST_PERSISTENT);
 	REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_SSLv23_CLIENT",	STREAM_CRYPTO_METHOD_SSLv23_CLIENT,	CONST_CS|CONST_PERSISTENT);
 	REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_TLS_CLIENT",		STREAM_CRYPTO_METHOD_TLS_CLIENT,	CONST_CS|CONST_PERSISTENT);
+	REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_STLS_CLIENT",		STREAM_CRYPTO_METHOD_STLS_CLIENT,	CONST_CS|CONST_PERSISTENT);
 	REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_SSLv2_SERVER",		STREAM_CRYPTO_METHOD_SSLv2_SERVER,	CONST_CS|CONST_PERSISTENT);
 	REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_SSLv3_SERVER",		STREAM_CRYPTO_METHOD_SSLv3_SERVER,	CONST_CS|CONST_PERSISTENT);
 	REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_SSLv23_SERVER",	STREAM_CRYPTO_METHOD_SSLv23_SERVER,	CONST_CS|CONST_PERSISTENT);
diff -ruN main/streams/php_stream_transport.h main/streams/php_stream_transport.h
--- main/streams/php_stream_transport.h	Wed Aug  3 10:08:42 2005
+++ main/streams/php_stream_transport.h	Sun Dec 18 04:18:16 2005
@@ -153,6 +153,7 @@
 	STREAM_CRYPTO_METHOD_SSLv3_CLIENT,
 	STREAM_CRYPTO_METHOD_SSLv23_CLIENT,
 	STREAM_CRYPTO_METHOD_TLS_CLIENT,
+	STREAM_CRYPTO_METHOD_STLS_CLIENT,
 	STREAM_CRYPTO_METHOD_SSLv2_SERVER,
 	STREAM_CRYPTO_METHOD_SSLv3_SERVER,
 	STREAM_CRYPTO_METHOD_SSLv23_SERVER,

Attachment: pgpULYQ14BMyy.pgp
Description: PGP signature

Reply via email to