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,
pgpULYQ14BMyy.pgp
Description: PGP signature