From bcadb6c94188e682b86462352c5ebacede47643c Mon Sep 17 00:00:00 2001 From: Eric Iversen Date: Fri, 26 Apr 2013 16:21:00 -0400 Subject: [PATCH] Added SoapClient constructor option 'ssl_method' to specify ssl method SSL behavior was defaulting to SSLv23 which will always send the Client Hello message in SSLv2. This sometimes results in a connection rejection when the SOAP server rejects any traffic using SSLv2. This occurs on many IIS web servers as well as Oracle/Sun web servers as well. SSLv2 has been deemed highly insecure and has been deprecated for some time. The new optional SoapClient constructor option: ssl_method, takes an argument from the list of constants defined below: SOAP_SSL_METHOD_TLS SOAP_SSL_METHOD_SSLv2 SOAP_SSL_METHOD_SSLv3 SOAP_SSL_METHOD_SSLv23 If the ssl_method option is not specified it will default to the behavior prior to this patch of using SSLv23. Specifying the SSL method will use the proper URI protocol of 'sslv2', 'sslv3', 'tls' or the default sslv23 URI protocol, 'ssl' when the PHP stream is created. If a proxy is specified in the SoapClient constructor and the connection is set to use SSL an unencrypted stream will first be created and encryption applied to the stream using the stream_socket_enable_crypto client methods. If no SSL method is specified in the SoapClient constructor the encryption method that is applied to an SSL connection through a proxy will be STREAM_CRYPTO_METHOD_SSLv23_CLIENT which is the current default behavior. The ability to specify an SSL method is important to implement as other PHP functions such as cURL have the ability to specify the SSL version to use. --- ext/soap/php_http.c | 66 +++++++++++++++++++++++++++++++++++++++++++-- ext/soap/php_soap.h | 7 +++++ ext/soap/soap.c | 11 ++++++++ 3 files changed, 82 insertions(+), 2 deletions(-) diff --git a/ext/soap/php_http.c b/ext/soap/php_http.c index 05918c72341f4..a5e67534ef3cf 100644 --- a/ext/soap/php_http.c +++ b/ext/soap/php_http.c @@ -162,6 +162,7 @@ static php_stream* http_connect(zval* this_ptr, php_url *phpurl, int use_ssl, ph zval **proxy_host, **proxy_port, **tmp; char *host; char *name; + char *protocol; long namelen; int port; int old_error_reporting; @@ -189,7 +190,41 @@ static php_stream* http_connect(zval* this_ptr, php_url *phpurl, int use_ssl, ph old_error_reporting = EG(error_reporting); EG(error_reporting) &= ~(E_WARNING|E_NOTICE|E_USER_WARNING|E_USER_NOTICE); - namelen = spprintf(&name, 0, "%s://%s:%d", (use_ssl && !*use_proxy)? "ssl" : "tcp", host, port); + /* Changed ternary operator to an if/else so that additional comparisons can be done on the ssl_method property */ + if (use_ssl && !*use_proxy) { + if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_ssl_method", sizeof("_ssl_method"), (void **) &tmp) == SUCCESS && + Z_TYPE_PP(tmp) == IS_LONG) { + /* uses contants declared in soap.c to determine ssl uri protocol */ + switch (Z_LVAL_PP(tmp)) { + case SOAP_SSL_METHOD_TLS: + protocol = "tls"; + break; + + case SOAP_SSL_METHOD_SSLv2: + protocol = "sslv2"; + break; + + case SOAP_SSL_METHOD_SSLv3: + protocol = "sslv3"; + break; + + case SOAP_SSL_METHOD_SSLv23: + protocol = "ssl"; + break; + + default: + protocol = "ssl"; + break; + + } + } else { + protocol = "ssl"; + } + } else { + protocol = "tcp"; + } + + namelen = spprintf(&name, 0, "%s://%s:%d", protocol, host, port); stream = php_stream_xport_create(name, namelen, ENFORCE_SAFE_MODE | REPORT_ERRORS, @@ -237,7 +272,34 @@ static php_stream* http_connect(zval* this_ptr, php_url *phpurl, int use_ssl, ph } /* enable SSL transport layer */ if (stream) { - if (php_stream_xport_crypto_setup(stream, STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL TSRMLS_CC) < 0 || + /* if a stream is created without encryption, check to see if SSL method parameter is specified and use + proper encrypyion method based on constants defined in soap.c */ + int crypto_method = STREAM_CRYPTO_METHOD_SSLv23_CLIENT; + if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_ssl_method", sizeof("_ssl_method"), (void **) &tmp) == SUCCESS && + Z_TYPE_PP(tmp) == IS_LONG) { + switch (Z_LVAL_PP(tmp)) { + case SOAP_SSL_METHOD_TLS: + crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT; + break; + + case SOAP_SSL_METHOD_SSLv2: + crypto_method = STREAM_CRYPTO_METHOD_SSLv2_CLIENT; + break; + + case SOAP_SSL_METHOD_SSLv3: + crypto_method = STREAM_CRYPTO_METHOD_SSLv3_CLIENT; + break; + + case SOAP_SSL_METHOD_SSLv23: + crypto_method = STREAM_CRYPTO_METHOD_SSLv23_CLIENT; + break; + + default: + crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT; + break; + } + } + if (php_stream_xport_crypto_setup(stream, crypto_method, NULL TSRMLS_CC) < 0 || php_stream_xport_crypto_enable(stream, 1 TSRMLS_CC) < 0) { php_stream_close(stream); stream = NULL; diff --git a/ext/soap/php_soap.h b/ext/soap/php_soap.h index 0e37db5d4cacc..7d0a3c16f1b9d 100644 --- a/ext/soap/php_soap.h +++ b/ext/soap/php_soap.h @@ -149,6 +149,13 @@ struct _soapService { #define WSDL_CACHE_MEMORY 0x2 #define WSDL_CACHE_BOTH 0x3 +/* New SOAP SSL Method Constants */ +#define SOAP_SSL_METHOD_TLS 0 +#define SOAP_SSL_METHOD_SSLv2 1 +#define SOAP_SSL_METHOD_SSLv3 2 +#define SOAP_SSL_METHOD_SSLv23 3 + + ZEND_BEGIN_MODULE_GLOBALS(soap) HashTable defEncNs; /* mapping of default namespaces to prefixes */ HashTable defEnc; diff --git a/ext/soap/soap.c b/ext/soap/soap.c index 6851a9b19c568..b0d7a74a8a881 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -864,6 +864,12 @@ PHP_MINIT_FUNCTION(soap) REGISTER_LONG_CONSTANT("WSDL_CACHE_MEMORY", WSDL_CACHE_MEMORY, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("WSDL_CACHE_BOTH", WSDL_CACHE_BOTH, CONST_CS | CONST_PERSISTENT); + /* New SOAP SSL Method Constants */ + REGISTER_LONG_CONSTANT("SOAP_SSL_METHOD_TLS", SOAP_SSL_METHOD_TLS, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SOAP_SSL_METHOD_SSLv2", SOAP_SSL_METHOD_SSLv2, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SOAP_SSL_METHOD_SSLv3", SOAP_SSL_METHOD_SSLv3, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SOAP_SSL_METHOD_SSLv23", SOAP_SSL_METHOD_SSLv23, CONST_CS | CONST_PERSISTENT); + old_error_handler = zend_error_cb; zend_error_cb = soap_error_handler; @@ -2691,6 +2697,11 @@ PHP_METHOD(SoapClient, SoapClient) Z_TYPE_PP(tmp) == IS_STRING) { add_property_stringl(this_ptr, "_user_agent", Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1); } + + if (zend_hash_find(ht, "ssl_method", sizeof("ssl_method"), (void**)&tmp) == SUCCESS && + Z_TYPE_PP(tmp) == IS_LONG) { + add_property_long(this_ptr, "_ssl_method", Z_LVAL_PP(tmp)); + } } else if (Z_TYPE_P(wsdl) == IS_NULL) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "'location' and 'uri' options are required in nonWSDL mode"); }