Perform SSL hostname validation

SSL stream can now verify that the remote server hostname matches the
the certificate Common Name or Subject Alternative Name.

This behavior can be disabled/enabled at the http_client scope using the
new function:

    axis2_http_client_set_validate_ssl_hostname

There is also an associated getter:

    axis2_http_client_get_validate_ssl_hostname

For backwards compatibility, this behavior is disabled by default.
However, this will change to being enabled by default in a future
release.

When enabled, this functionality mitigates CVE-2012-6107.

JIRA: AXIS2C-1619
diff --git a/include/axis2_http_client.h b/include/axis2_http_client.h
index a7b2dbc..edbfc3f 100644
--- a/include/axis2_http_client.h
+++ b/include/axis2_http_client.h
@@ -271,6 +271,18 @@
         axis2_http_client_t * client,
         const axutil_env_t * env);
 
+    AXIS2_EXTERN axis2_status_t AXIS2_CALL
+    axis2_http_client_set_validate_ssl_hostname(
+        axis2_http_client_t * client,
+        const axutil_env_t * env,
+        axis2_bool_t validate_host);
+
+    AXIS2_EXTERN axis2_bool_t AXIS2_CALL
+    axis2_http_client_get_validate_ssl_hostname(
+        const axis2_http_client_t * client,
+        const axutil_env_t * env);
+
+
 
     /** @} */
 #ifdef __cplusplus
diff --git a/src/core/transport/http/sender/http_client.c b/src/core/transport/http/sender/http_client.c
index eff988e..6be601b 100644
--- a/src/core/transport/http/sender/http_client.c
+++ b/src/core/transport/http/sender/http_client.c
@@ -52,6 +52,7 @@
     axis2_char_t *key_file;
     axis2_char_t *req_body;
     int req_body_size;
+    axis2_bool_t validate_ssl_hostname;
 
     /* These are for mtom case */
     axutil_array_list_t *mime_parts;
@@ -97,6 +98,11 @@
     http_client->doing_mtom = AXIS2_FALSE;
     http_client->mtom_sending_callback_name = NULL;
 
+    /* TODO default this to false for now, but this should default
+     * to true in a future version (after 1.8)
+     */
+    http_client->validate_ssl_hostname = AXIS2_FALSE;
+
     return http_client;
 }
 
@@ -277,7 +283,8 @@
 		if(!client->data_stream)
 			client->data_stream =
 			axutil_stream_create_ssl(env, client->sockfd, axis2_http_client_get_server_cert(client,
-                env), axis2_http_client_get_key_file(client, env), ssl_pp);
+                env), axis2_http_client_get_key_file(client, env), ssl_pp,
+                    client->validate_ssl_hostname == AXIS2_TRUE ? host : NULL);
 #else
         axutil_network_handler_close_socket(env, client->sockfd);
         client->sockfd = -1;
@@ -1052,3 +1059,22 @@
     }
     return AXIS2_SUCCESS;
 }
+
+AXIS2_EXTERN axis2_status_t AXIS2_CALL
+axis2_http_client_set_validate_ssl_hostname(
+        axis2_http_client_t * client,
+        const axutil_env_t * env,
+        axis2_bool_t validate_ssl_hostname)
+{
+    client->validate_ssl_hostname = validate_ssl_hostname;
+    return AXIS2_SUCCESS;
+}
+
+AXIS2_EXTERN axis2_bool_t AXIS2_CALL
+axis2_http_client_get_validate_ssl_hostname(
+        const axis2_http_client_t * client,
+        const axutil_env_t * env)
+{
+    return client->validate_ssl_hostname;
+}
+
diff --git a/src/core/transport/http/sender/ssl/ssl_stream.c b/src/core/transport/http/sender/ssl/ssl_stream.c
index 50272c5..e3d9e16 100644
--- a/src/core/transport/http/sender/ssl/ssl_stream.c
+++ b/src/core/transport/http/sender/ssl/ssl_stream.c
@@ -69,7 +69,8 @@
     axis2_socket_t socket,
     axis2_char_t * server_cert,
     axis2_char_t * key_file,
-    axis2_char_t * ssl_pp)
+    axis2_char_t * ssl_pp,
+    axis2_char_t * host)
 {
     ssl_stream_impl_t *stream_impl = NULL;
 
@@ -96,7 +97,7 @@
         return NULL;
     }
     stream_impl->ssl = axis2_ssl_utils_initialize_ssl(env, stream_impl->ctx,
-        stream_impl->socket);
+        stream_impl->socket, host);
     if (!stream_impl->ssl)
     {
         AXIS2_HANDLE_ERROR(env, AXIS2_ERROR_SSL_ENGINE, AXIS2_FAILURE);
diff --git a/src/core/transport/http/sender/ssl/ssl_stream.h b/src/core/transport/http/sender/ssl/ssl_stream.h
index 7d1ef09..2df504d 100644
--- a/src/core/transport/http/sender/ssl/ssl_stream.h
+++ b/src/core/transport/http/sender/ssl/ssl_stream.h
@@ -38,7 +38,8 @@
         axis2_socket_t socket,
         axis2_char_t * server_cert,
         axis2_char_t * key_file,
-        axis2_char_t * ssl_pp);
+        axis2_char_t * ssl_pp,
+        axis2_char_t * host);
 
 	void AXIS2_CALL
 	axis2_ssl_stream_free(
diff --git a/src/core/transport/http/sender/ssl/ssl_utils.c b/src/core/transport/http/sender/ssl/ssl_utils.c
index a904883..8f86e2d 100644
--- a/src/core/transport/http/sender/ssl/ssl_utils.c
+++ b/src/core/transport/http/sender/ssl/ssl_utils.c
@@ -171,7 +171,8 @@
 axis2_ssl_utils_initialize_ssl(
     const axutil_env_t * env,
     SSL_CTX * ctx,
-    axis2_socket_t socket)
+    axis2_socket_t socket,
+    axis2_char_t * host)
 {
     SSL *ssl = NULL;
     BIO *sbio = NULL;
@@ -242,6 +243,17 @@
 
                 if (ASN1_STRING_cmp(peer_sig, client_sig) == 0)
                 {
+                    /* if the caller passed a hostname, verify it against the cert */
+                    if (host) {
+                        if (X509_check_host(peer_cert, host, strlen(host), 0, NULL) == 1) {
+                            AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI,
+                                    "[ssl client] peer name matches certificate CN/SAN");
+                        } else {
+                            AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI,
+                                    "[ssl client] peer name does not match certificate CN/SAN");
+                            return NULL;
+                        }
+                    }
                     if (peer_cert)
                     {
                         X509_free(peer_cert);
diff --git a/src/core/transport/http/sender/ssl/ssl_utils.h b/src/core/transport/http/sender/ssl/ssl_utils.h
index 26dc16b..29f00ad 100644
--- a/src/core/transport/http/sender/ssl/ssl_utils.h
+++ b/src/core/transport/http/sender/ssl/ssl_utils.h
@@ -41,7 +41,8 @@
     axis2_ssl_utils_initialize_ssl(
         const axutil_env_t * env,
         SSL_CTX * ctx,
-        axis2_socket_t socket);
+        axis2_socket_t socket,
+        axis2_char_t * host);
 
     AXIS2_EXTERN axis2_status_t AXIS2_CALL
     axis2_ssl_utils_cleanup_ssl(