소스 검색

Merge pull request #481 from kamailio/tmp/hpw_curl_improvements

curl: Add various curl and TLS options to curl module
- client key/certificate
- cacert
- sslversion
- cipher suites
- verify_host and verify_peer
Hugh Waite 9 년 전
부모
커밋
1b6fe67edf
5개의 변경된 파일268개의 추가작업 그리고 81개의 파일을 삭제
  1. 19 17
      modules/curl/curl.c
  2. 17 10
      modules/curl/curl.h
  3. 70 10
      modules/curl/curlcon.c
  4. 64 5
      modules/curl/doc/curl_admin.xml
  5. 98 39
      modules/curl/functions.c

+ 19 - 17
modules/curl/curl.c

@@ -74,13 +74,16 @@ MODULE_VERSION
 /* Module parameter variables */
 /* Module parameter variables */
 unsigned int	default_connection_timeout = 4;
 unsigned int	default_connection_timeout = 4;
 char		*default_tls_cacert = NULL;		/*!< File name: Default CA cert to use for curl TLS connection */
 char		*default_tls_cacert = NULL;		/*!< File name: Default CA cert to use for curl TLS connection */
-char		*default_tls_clientcert = NULL;		/*!< File name: Default client certificate to use for curl TLS connection */
-char		*default_tls_clientkey = NULL;		/*!< File name: Key in PEM format that belongs to client cert */
-unsigned int	default_tls_verifyserver = 1;		/*!< 0 = Do not verify TLS server cert. 1 = Verify TLS cert (default) */
+str		default_tls_clientcert = STR_NULL;		/*!< File name: Default client certificate to use for curl TLS connection */
+str		default_tls_clientkey = STR_NULL;		/*!< File name: Key in PEM format that belongs to client cert */
+str		default_cipher_suite_list = STR_NULL;		/*!< List of allowed cipher suites */
+unsigned int	default_tls_version = 0;		/*!< 0 = Use libcurl default */
+unsigned int	default_tls_verify_peer = 1;		/*!< 0 = Do not verify TLS server cert. 1 = Verify TLS cert (default) */
+unsigned int	default_tls_verify_host = 2;		/*!< 0 = Do not verify TLS server CN/SAN  2 = Verify TLS server CN/SAN (default) */
 char 		*default_http_proxy = NULL;		/*!< Default HTTP proxy to use */
 char 		*default_http_proxy = NULL;		/*!< Default HTTP proxy to use */
 unsigned int	default_http_proxy_port = 0;		/*!< Default HTTP proxy port to use */
 unsigned int	default_http_proxy_port = 0;		/*!< Default HTTP proxy port to use */
 unsigned int	default_http_follow_redirect = 0;	/*!< Follow HTTP redirects CURLOPT_FOLLOWLOCATION */
 unsigned int	default_http_follow_redirect = 0;	/*!< Follow HTTP redirects CURLOPT_FOLLOWLOCATION */
-char 		*default_useragent = CURL_USER_AGENT;	/*!< Default CURL useragent. Default "Kamailio Curl " */
+str 		default_useragent = { CURL_USER_AGENT, CURL_USER_AGENT_LEN };	/*!< Default CURL useragent. Default "Kamailio Curl " */
 unsigned int	default_maxdatasize = 0;		/*!< Default download size. 0=disabled */
 unsigned int	default_maxdatasize = 0;		/*!< Default download size. 0=disabled */
 
 
 static curl_version_info_data *curl_info;
 static curl_version_info_data *curl_info;
@@ -137,24 +140,20 @@ static param_export_t params[] = {
     	{"connection_timeout", PARAM_INT, &default_connection_timeout},
     	{"connection_timeout", PARAM_INT, &default_connection_timeout},
 	{"curlcon",  PARAM_STRING|USE_FUNC_PARAM, (void*)curl_con_param},
 	{"curlcon",  PARAM_STRING|USE_FUNC_PARAM, (void*)curl_con_param},
 	{"tlscacert", PARAM_STRING,  &default_tls_cacert },
 	{"tlscacert", PARAM_STRING,  &default_tls_cacert },
-	{"tlsclientcert", PARAM_STRING, &default_tls_clientcert },
-	{"tlsclientkey", PARAM_STRING, &default_tls_clientkey },
-	{"tlsverifyserver", PARAM_INT, &default_tls_verifyserver },
+	{"tlsclientcert", PARAM_STR, &default_tls_clientcert },
+	{"tlsclientkey", PARAM_STR, &default_tls_clientkey },
+	{"tlscipherlist", PARAM_STR, &default_cipher_suite_list },
+	{"tlsversion", PARAM_INT, &default_tls_version },
+	{"tlsverifypeer", PARAM_INT, &default_tls_verify_peer },
+	{"tlsverifyhost", PARAM_INT, &default_tls_verify_host },
 	{"httpproxyport", PARAM_INT, &default_http_proxy_port },
 	{"httpproxyport", PARAM_INT, &default_http_proxy_port },
 	{"httpproxy", PARAM_STRING, &default_http_proxy},
 	{"httpproxy", PARAM_STRING, &default_http_proxy},
 	{"httpredirect", PARAM_INT, &default_http_follow_redirect },
 	{"httpredirect", PARAM_INT, &default_http_follow_redirect },
-	{"useragent", PARAM_STRING,  &default_useragent },
+	{"useragent", PARAM_STR,  &default_useragent },
 	{"maxdatasize", PARAM_INT,  &default_maxdatasize },
 	{"maxdatasize", PARAM_INT,  &default_maxdatasize },
     	{0, 0, 0}
     	{0, 0, 0}
 };
 };
 
 
-//		str	default_tls_clientcert;			/*!< File name: Default client certificate to use for curl TLS connection */
-//		str	default_tls_clientkey;			/*!< File name: Key in PEM format that belongs to client cert */
-//		int	default_tls_verifyserver = 1;		/*!< 0 = Do not verify TLS server cert. 1 = Verify TLS cert (default) */
-//		str	default_http_proxy;			/*!< Default HTTP proxy to use */
-//		int	default_http_proxy_port;		/*!< Default HTTP proxy port to use */
-//		int	default_http_follow_redirect = 0;	/*!< Follow HTTP redirects CURLOPT_FOLLOWLOCATION */
-//		str	default_useragent;			/*!< Default CURL useragent. Default "Kamailio Curl " */
 
 
 /*!
 /*!
  * \brief Exported Pseudo variables
  * \brief Exported Pseudo variables
@@ -249,10 +248,13 @@ static int mod_init(void)
 
 
 	LM_DBG("**** init curl module done. Curl version: %s SSL %s\n", curl_info->version, curl_info->ssl_version);
 	LM_DBG("**** init curl module done. Curl version: %s SSL %s\n", curl_info->version, curl_info->ssl_version);
 	LM_DBG("**** init curl: Number of connection objects: %d \n", curl_connection_count());
 	LM_DBG("**** init curl: Number of connection objects: %d \n", curl_connection_count());
-	LM_DBG("**** init curl: User Agent: %s \n", default_useragent);
+	LM_DBG("**** init curl: User Agent: %.*s \n", default_useragent.len, default_useragent.s);
 	LM_DBG("**** init curl: HTTPredirect: %d \n", default_http_follow_redirect);
 	LM_DBG("**** init curl: HTTPredirect: %d \n", default_http_follow_redirect);
-	LM_DBG("**** init curl: Client Cert: %s Key %s\n", default_tls_clientcert, default_tls_clientkey);
+	LM_DBG("**** init curl: Client Cert: %.*s Key %.*s\n", default_tls_clientcert.len, default_tls_clientcert.s, default_tls_clientkey.len, default_tls_clientkey.s);
 	LM_DBG("**** init curl: CA Cert: %s \n", default_tls_cacert);
 	LM_DBG("**** init curl: CA Cert: %s \n", default_tls_cacert);
+	LM_DBG("**** init curl: Cipher Suites: %.*s \n", default_cipher_suite_list.len, default_cipher_suite_list.s);
+	LM_DBG("**** init curl: SSL Version: %d \n", default_tls_version);
+	LM_DBG("**** init curl: verifypeer: %d verifyhost: %d\n", default_tls_verify_peer, default_tls_verify_host);
 	LM_DBG("**** init curl: HTTP Proxy: %s Port %d\n", default_http_proxy, default_http_proxy_port);
 	LM_DBG("**** init curl: HTTP Proxy: %s Port %d\n", default_http_proxy, default_http_proxy_port);
 
 
 	LM_DBG("Extra: Curl supports %s %s %s \n",
 	LM_DBG("Extra: Curl supports %s %s %s \n",

+ 17 - 10
modules/curl/curl.h

@@ -37,13 +37,16 @@
 
 
 extern unsigned int	default_connection_timeout;
 extern unsigned int	default_connection_timeout;
 extern char	*default_tls_cacert;			/*!< File name: Default CA cert to use for curl TLS connection */
 extern char	*default_tls_cacert;			/*!< File name: Default CA cert to use for curl TLS connection */
-extern char	*default_tls_clientcert;		/*!< File name: Default client certificate to use for curl TLS connection */
-extern char	*default_tls_clientkey;			/*!< File name: Key in PEM format that belongs to client cert */
-extern unsigned int	default_tls_verifyserver;		/*!< 0 = Do not verify TLS server cert. 1 = Verify TLS cert (default) */
+extern str	default_tls_clientcert;		/*!< File name: Default client certificate to use for curl TLS connection */
+extern str	default_tls_clientkey;			/*!< File name: Key in PEM format that belongs to client cert */
+extern str	default_cipher_suite_list;			/*!< List of allowed cipher suites */
+extern unsigned int	default_tls_version;		/*!< 0 = Use libcurl default */
+extern unsigned int	default_tls_verify_peer;	/*!< 0 = Do not verify TLS server cert. 1 = Verify TLS cert (default) */
+extern unsigned int	default_tls_verify_host;	/*!< 0 = Do not verify TLS server CN/SAN. 2 = Verify TLS server CN/SAN (default) */
 extern char 	*default_http_proxy;			/*!< Default HTTP proxy to use */
 extern char 	*default_http_proxy;			/*!< Default HTTP proxy to use */
 extern unsigned int	default_http_proxy_port;		/*!< Default HTTP proxy port to use */
 extern unsigned int	default_http_proxy_port;		/*!< Default HTTP proxy port to use */
 extern unsigned int	default_http_follow_redirect;	/*!< Follow HTTP redirects CURLOPT_FOLLOWLOCATION */
 extern unsigned int	default_http_follow_redirect;	/*!< Follow HTTP redirects CURLOPT_FOLLOWLOCATION */
-extern char 	*default_useragent;			/*!< Default CURL useragent. Default "Kamailio Curl " */
+extern str 	default_useragent;			/*!< Default CURL useragent. Default "Kamailio Curl " */
 extern unsigned int	default_maxdatasize;			/*!< Default Maximum download size */
 extern unsigned int	default_maxdatasize;			/*!< Default Maximum download size */
 
 
 extern counter_handle_t connections;	/* Number of connection definitions */
 extern counter_handle_t connections;	/* Number of connection definitions */
@@ -66,13 +69,17 @@ typedef struct _curl_con
 	unsigned int conid;		/*!< Connection ID */
 	unsigned int conid;		/*!< Connection ID */
 	str url;			/*!< The URL without schema (host + base URL)*/
 	str url;			/*!< The URL without schema (host + base URL)*/
 	str schema;			/*!< The URL schema */
 	str schema;			/*!< The URL schema */
-	str username;			/*!< The username to use for auth */
-	str password;			/*!< The password to use for auth */
+	char *username;			/*!< The username to use for auth */
+	char *password;			/*!< The password to use for auth */
 	str failover;			/*!< Another connection to use if this one fails */
 	str failover;			/*!< Another connection to use if this one fails */
-	str cacert;			/*!< File name of CA cert to use */
-	str clientcert;			/*!< File name of CA client cert */
-	str useragent;			/*!< Useragent to use for this connection */
-	int tls_verifyserver;		/*!< TRUE if server cert needs to be verified */
+	char *useragent;		/*!< Useragent to use for this connection */
+	char *cacert;			/*!< File name of CA cert to use */
+	char *clientcert;		/*!< File name of CA client cert */
+	char *clientkey;		/*!< File name of CA client key */
+	char *ciphersuites;		/*!< List of allowed cipher suites */
+	unsigned int sslversion;	/*!< SSL/TLS version to use */
+	unsigned int verify_peer;	/*!< TRUE if server cert to be verified */
+	unsigned int verify_host;	/*!< TRUE if server CN/SAN to be verified */
 	int http_follow_redirect;	/*!< TRUE if we should follow HTTP 302 redirects */
 	int http_follow_redirect;	/*!< TRUE if we should follow HTTP 302 redirects */
 	unsigned int port;		/*!< The port to connect to */
 	unsigned int port;		/*!< The port to connect to */
 	int timeout;			/*!< Timeout for this connection */
 	int timeout;			/*!< Timeout for this connection */

+ 70 - 10
modules/curl/curlcon.c

@@ -26,6 +26,8 @@
  * \ingroup curl
  * \ingroup curl
  */
  */
 
 
+#include <curl/curl.h>
+
 #include "../../hashes.h"
 #include "../../hashes.h"
 #include "../../dprint.h"
 #include "../../dprint.h"
 #include "../../parser/parse_param.h"
 #include "../../parser/parse_param.h"
@@ -96,6 +98,8 @@ curl_con_t* curl_get_connection(str *name)
  *		useragent
  *		useragent
  *		failover
  *		failover
  *		maxdatasize
  *		maxdatasize
+ *		verifypeer
+ *		verifyhost
  *
  *
  */
  */
 int curl_parse_param(char *val)
 int curl_parse_param(char *val)
@@ -108,10 +112,17 @@ int curl_parse_param(char *val)
 	str params	= STR_NULL;
 	str params	= STR_NULL;
 	str failover	= STR_NULL;
 	str failover	= STR_NULL;
 
 
+	str client_cert  = default_tls_clientcert;
+	str client_key   = default_tls_clientkey;
+	str ciphersuites = default_cipher_suite_list;
+	str useragent    = default_useragent;
+
 	unsigned int maxdatasize = default_maxdatasize;
 	unsigned int maxdatasize = default_maxdatasize;
 	unsigned int timeout	= default_connection_timeout;
 	unsigned int timeout	= default_connection_timeout;
-	str useragent   = { default_useragent, strlen(default_useragent) };
 	unsigned int http_follow_redirect = default_http_follow_redirect;
 	unsigned int http_follow_redirect = default_http_follow_redirect;
+	unsigned int verify_peer = default_tls_verify_peer;
+	unsigned int verify_host = default_tls_verify_host;
+	unsigned int sslversion = default_tls_version;
 
 
 	str in;
 	str in;
 	char *p;
 	char *p;
@@ -119,8 +130,6 @@ int curl_parse_param(char *val)
 	param_t *conparams = NULL;
 	param_t *conparams = NULL;
 	curl_con_t *cc;
 	curl_con_t *cc;
 
 
-	username.len = 0;
-	password.len = 0;
 	LM_INFO("curl modparam parsing starting\n");
 	LM_INFO("curl modparam parsing starting\n");
 	LM_DBG("modparam curlcon: %s\n", val);
 	LM_DBG("modparam curlcon: %s\n", val);
 
 
@@ -300,6 +309,47 @@ int curl_parse_param(char *val)
 					maxdatasize = default_maxdatasize;
 					maxdatasize = default_maxdatasize;
 				}
 				}
 				LM_DBG("curl [%.*s] - timeout [%d]\n", pit->name.len, pit->name.s, maxdatasize);
 				LM_DBG("curl [%.*s] - timeout [%d]\n", pit->name.len, pit->name.s, maxdatasize);
+			} else if(pit->name.len==10 && strncmp(pit->name.s, "verifypeer", 10)==0) {
+				if(str2int(&tok, &verify_peer)!=0) {
+					/* Bad integer */
+					LM_DBG("curl connection [%.*s]: verifypeer bad value. Using default\n", name.len, name.s);
+					verify_peer = default_tls_verify_peer;
+				}
+				if (verify_peer != 0 && verify_peer != 1) {
+					LM_DBG("curl connection [%.*s]: verifypeer bad value. Using default\n", name.len, name.s);
+					verify_peer = default_tls_verify_peer;
+				}
+				LM_DBG("curl [%.*s] - verifypeer [%d]\n", pit->name.len, pit->name.s, verify_peer);
+			} else if(pit->name.len==10 && strncmp(pit->name.s, "verifyhost", 10)==0) {
+				if(str2int(&tok, &verify_host)!=0) {
+					/* Bad integer */
+					LM_DBG("curl connection [%.*s]: verifyhost bad value. Using default\n", name.len, name.s);
+					verify_host = default_tls_verify_host;
+				}
+				LM_DBG("curl [%.*s] - verifyhost [%d]\n", pit->name.len, pit->name.s, verify_host);
+			} else if(pit->name.len==10 && strncmp(pit->name.s, "sslversion", 10)==0) {
+				if(str2int(&tok, &sslversion)!=0) {
+					/* Bad integer */
+					LM_DBG("curl connection [%.*s]: sslversion bad value. Using default\n", name.len, name.s);
+					sslversion = default_tls_version;
+				}
+				if (sslversion >= CURL_SSLVERSION_LAST) {
+					LM_DBG("curl connection [%.*s]: sslversion bad value. Using default\n", name.len, name.s);
+					sslversion = default_tls_version;
+				}
+				LM_DBG("curl [%.*s] - sslversion [%d]\n", pit->name.len, pit->name.s, sslversion);
+			} else if(pit->name.len==10 && strncmp(pit->name.s, "clientcert", 10)==0) {
+				client_cert = tok;
+				LM_DBG("curl [%.*s] - clientcert [%.*s]\n", pit->name.len, pit->name.s,
+						client_cert.len, client_cert.s);
+			} else if(pit->name.len==9 && strncmp(pit->name.s, "clientkey", 9)==0) {
+				client_key = tok;
+				LM_DBG("curl [%.*s] - clientkey [%.*s]\n", pit->name.len, pit->name.s,
+						client_key.len, client_key.s);
+			} else if(pit->name.len==12 && strncmp(pit->name.s, "ciphersuites", 12)==0) {
+				ciphersuites = tok;
+				LM_DBG("curl [%.*s] - ciphersuites [%.*s]\n", pit->name.len, pit->name.s,
+						ciphersuites.len, ciphersuites.s);
 			} else {
 			} else {
 				LM_ERR("curl Unknown parameter [%.*s] \n", pit->name.len, pit->name.s);
 				LM_ERR("curl Unknown parameter [%.*s] \n", pit->name.len, pit->name.s);
 			}
 			}
@@ -308,10 +358,6 @@ int curl_parse_param(char *val)
 
 
 	/* The URL ends either with nothing or parameters. Parameters start with ; */
 	/* The URL ends either with nothing or parameters. Parameters start with ; */
 
 
-	LM_DBG("cname: [%.*s] url: [%.*s] username [%.*s] password [%.*s] failover [%.*s] timeout [%d] useragent [%.*s] maxdatasize [%d]\n", 
-			name.len, name.s, url.len, url.s, username.len, username.s,
-			password.len, password.s, failover.len, failover.s, timeout, useragent.len, useragent.s, maxdatasize);
-
 	if(conparams != NULL) {
 	if(conparams != NULL) {
 		free_params(conparams);
 		free_params(conparams);
 	}
 	}
@@ -320,15 +366,29 @@ int curl_parse_param(char *val)
 	if (cc == NULL) {
 	if (cc == NULL) {
 		return -1;
 		return -1;
 	}
 	}
-	cc->username = username;
-	cc->password = password;
+
+	cc->username = username.s ? as_asciiz(&username) : NULL;
+	cc->password = password.s ? as_asciiz(&password) : NULL;
 	cc->schema = schema;
 	cc->schema = schema;
 	cc->failover = failover;
 	cc->failover = failover;
-	cc->useragent = useragent;
+	cc->useragent = as_asciiz(&useragent);
 	cc->url = url;
 	cc->url = url;
+	cc->clientcert = client_cert.s ? as_asciiz(&client_cert) : NULL;
+	cc->clientkey = client_key.s ? as_asciiz(&client_key) : NULL;
+	cc->ciphersuites = ciphersuites.s ? as_asciiz(&ciphersuites) : NULL;
+	cc->sslversion = sslversion;
+	cc->verify_peer = verify_peer;
+	cc->verify_host = verify_host;
 	cc->timeout = timeout;
 	cc->timeout = timeout;
 	cc->maxdatasize = maxdatasize;
 	cc->maxdatasize = maxdatasize;
 	cc->http_follow_redirect = http_follow_redirect;
 	cc->http_follow_redirect = http_follow_redirect;
+
+	LM_DBG("cname: [%.*s] url: [%.*s] username [%s] password [%s] failover [%.*s] timeout [%d] useragent [%s] maxdatasize [%d]\n", 
+			name.len, name.s, cc->url.len, cc->url.s, cc->username ? cc->username : "", cc->password ? cc->password : "",
+			cc->failover.len, cc->failover.s, cc->timeout, cc->useragent, cc->maxdatasize);
+	LM_DBG("cname: [%.*s] client_cert [%s] client_key [%s] ciphersuites [%s] sslversion [%d] verify_peer [%d] verify_host [%d]\n",
+			name.len, name.s, cc->clientcert, cc->clientkey, cc->ciphersuites, cc->sslversion, cc->verify_peer, cc->verify_host);
+
 	return 0;
 	return 0;
 
 
 error:
 error:

+ 64 - 5
modules/curl/doc/curl_admin.xml

@@ -223,8 +223,30 @@ modparam("curl", "tlscacert", "/var/certs/ca/edvina-sip-ca.pem")
 				</programlisting>
 				</programlisting>
 			</example>
 			</example>
 		</section>
 		</section>
-		<section id="curl.p.tlsverifyserver">
-			<title><varname>tlsverifyserver</varname> (int)</title>
+		<section id="curl.p.tlscipherlist">
+			<title><varname>tlscipherlist</varname> (string)</title>
+			<para>
+			List of allowed cipher suites.
+			See http://curl.haxx.se/libcurl/c/CURLOPT_SSL_CIPHER_LIST.html for details
+			of the cipher list curl option.
+			</para>
+			<para>
+			<emphasis>
+				Default value is empty string, i.e.
+				the default list of ciphers in libcurl will be used.
+			</emphasis>
+			</para>
+			<example>
+			<title>Set <varname>tlscipherlist</varname> parameter</title>
+				<programlisting format="linespecific">
+...
+modparam("curl", "tlscipherlist", "ecdhe_ecdsa_aes_128_gcm_sha_256,rsa_aes_128_gcm_sha_256")
+...
+				</programlisting>
+			</example>
+		</section>
+		<section id="curl.p.tlsverifypeer">
+			<title><varname>tlsverifypeer</varname> (int)</title>
 			<para>
 			<para>
 			If set to 0, TLS verification of the server certificate
 			If set to 0, TLS verification of the server certificate
 			is disabled. This means that the connection will get 
 			is disabled. This means that the connection will get 
@@ -233,17 +255,45 @@ modparam("curl", "tlscacert", "/var/certs/ca/edvina-sip-ca.pem")
 			that is meant to receive data.
 			that is meant to receive data.
 			</para>
 			</para>
 			<para>
 			<para>
-			IF set to 1, default setting, and one or more CA certificates
+			If set to 1, default setting, and one or more CA certificates
 			is configured, the server TLS certificate will be validated.
 			is configured, the server TLS certificate will be validated.
 			If validation fails, the connection fails.
 			If validation fails, the connection fails.
 			</para>
 			</para>
 			<para>
 			<para>
+			See the curl documenation for more details.
+			http://curl.haxx.se/libcurl/c/CURLOPT_SSL_VERIFYPEER.html
 			</para>
 			</para>
 			<example>
 			<example>
-			<title>Set <varname>tlsverifyserver</varname> parameter</title>
+			<title>Set <varname>tlsverifypeer</varname> parameter</title>
 				<programlisting format="linespecific">
 				<programlisting format="linespecific">
 ...
 ...
-modparam("curl", "tlsverifyserver", 1)
+modparam("curl", "tlsverifypeer", 1)
+...
+				</programlisting>
+			</example>
+		</section>
+		<section id="curl.p.tlsverifyhost">
+			<title><varname>tlsverifyhost</varname> (int)</title>
+			<para>
+			If set to 0, domain verification of the server certificate
+			is disabled. This means that the connection will get 
+			encrypted but there is no check that data will be sent to the
+			host that is meant to receive it. Disable with caution.
+			</para>
+			<para>
+			If set to 2, default setting, the hostname in the URL will
+			be verified against the Common Name or Subject Alt Name
+			in the certificate. If validation fails, the connection fails.
+			</para>
+			<para>
+			See the curl documentation for more details.
+			http://curl.haxx.se/libcurl/c/CURLOPT_SSL_VERIFYHOST.html
+			</para>
+			<example>
+			<title>Set <varname>tlsverifyhost</varname> parameter</title>
+				<programlisting format="linespecific">
+...
+modparam("curl", "tlsverifyhost", 2)
 ...
 ...
 				</programlisting>
 				</programlisting>
 			</example>
 			</example>
@@ -286,6 +336,15 @@ modparam("curl", "tlsverifyserver", 1)
 				<emphasis>useragent</emphasis> Useragent used for HTTP requests. Overrides
 				<emphasis>useragent</emphasis> Useragent used for HTTP requests. Overrides
 				useragent modparam.
 				useragent modparam.
 				</para></listitem>
 				</para></listitem>
+				<listitem><para>
+				<emphasis>verifypeer</emphasis> Set to 1 to enable or 0 to disable server
+				certificate verification.
+				Overrides tlsverifypeer modparam.
+				</para></listitem>
+				<emphasis>verifyhost</emphasis> Set to 2 to enable or 0 to disable server
+				hostname verification.
+				Overrides tlsverifyhost modparam.
+				</para></listitem>
 			</itemizedlist>
 			</itemizedlist>
 			</para>
 			</para>
 			<example>
 			<example>

+ 98 - 39
modules/curl/functions.c

@@ -45,10 +45,27 @@
 #include "curl.h"
 #include "curl.h"
 #include "curlcon.h"
 #include "curlcon.h"
 
 
+
+typedef struct {
+    char *username;
+    char *secret;
+    char *contenttype;
+    char *post;
+    char *clientcert;
+    char *clientkey;
+    char *cacert;
+    char *ciphersuites;
+    unsigned int sslversion;
+    unsigned int verify_peer;
+    unsigned int verify_host;
+    unsigned int timeout;
+    unsigned int http_follow_redirect;
+    unsigned int oneline;
+    unsigned int maxdatasize;
+} curl_query_t;
+
 /* Forward declaration */
 /* Forward declaration */
-static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst, const char *username,
-		const char *secret, const char *contenttype, const char* _post, const unsigned int timeout,
-		unsigned int http_follow_redirect, unsigned int oneline, unsigned int maxdatasize);
+static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst, const curl_query_t * const query_params);
 
 
 /* 
 /* 
  * curl write function that saves received data as zero terminated
  * curl write function that saves received data as zero terminated
@@ -86,7 +103,7 @@ size_t write_function( void *ptr, size_t size, size_t nmemb, void *stream_ptr)
 
 
 /*! Send query to server, optionally post data.
 /*! Send query to server, optionally post data.
  */
  */
-static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst, const char *_username, const char *_secret, const char *contenttype, const char* _post, unsigned int timeout, unsigned int http_follow_redirect, unsigned int oneline, unsigned int maxdatasize)
+static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst, const curl_query_t * const params)
 {
 {
     CURL *curl;
     CURL *curl;
     CURLcode res;  
     CURLcode res;  
@@ -99,7 +116,7 @@ static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst, const
     struct curl_slist *headerlist = NULL;
     struct curl_slist *headerlist = NULL;
 
 
     memset(&stream, 0, sizeof(curl_res_stream_t));
     memset(&stream, 0, sizeof(curl_res_stream_t));
-    stream.max_size = (size_t) maxdatasize;
+    stream.max_size = (size_t) params->maxdatasize;
 
 
     curl = curl_easy_init();
     curl = curl_easy_init();
     if (curl == NULL) {
     if (curl == NULL) {
@@ -110,11 +127,11 @@ static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst, const
     LM_DBG("****** ##### CURL URL [%s] \n", _url);
     LM_DBG("****** ##### CURL URL [%s] \n", _url);
     res = curl_easy_setopt(curl, CURLOPT_URL, _url);
     res = curl_easy_setopt(curl, CURLOPT_URL, _url);
 
 
-    if (_post) {
+    if (params->post) {
 	char ctype[256];
 	char ctype[256];
 
 
 	ctype[0] = '\0';
 	ctype[0] = '\0';
-	snprintf(ctype, sizeof(ctype), "Content-Type: %s", contenttype);
+	snprintf(ctype, sizeof(ctype), "Content-Type: %s", params->contenttype);
 
 
         /* Now specify we want to POST data */ 
         /* Now specify we want to POST data */ 
 	res |= curl_easy_setopt(curl, CURLOPT_POST, 1L);
 	res |= curl_easy_setopt(curl, CURLOPT_POST, 1L);
@@ -124,28 +141,51 @@ static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst, const
 
 
 	/* Tell CURL we want to upload using POST */
 	/* Tell CURL we want to upload using POST */
 
 
- 	res |= curl_easy_setopt(curl, CURLOPT_POSTFIELDS, _post);
+	res |= curl_easy_setopt(curl, CURLOPT_POSTFIELDS, params->post);
 
 
     }
     }
 
 
-    if (maxdatasize) {
+    if (params->maxdatasize) {
 	/* Maximum data size to download - we always download full response, but
 	/* Maximum data size to download - we always download full response, but
 	   cut it off before moving to pvar */
 	   cut it off before moving to pvar */
-    	LM_DBG("****** ##### CURL Max datasize %u\n", maxdatasize);
+	LM_DBG("****** ##### CURL Max datasize %u\n", params->maxdatasize);
     }
     }
 
 
-    if (_username) {
- 	res |= curl_easy_setopt(curl, CURLOPT_USERNAME, _username);
+    if (params->username) {
+	res |= curl_easy_setopt(curl, CURLOPT_USERNAME, params->username);
 	res |= curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (CURLAUTH_DIGEST|CURLAUTH_BASIC));
 	res |= curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (CURLAUTH_DIGEST|CURLAUTH_BASIC));
     }
     }
-    if (_secret) {
- 	res |= curl_easy_setopt(curl, CURLOPT_PASSWORD, _secret);
+    if (params->secret) {
+	res |= curl_easy_setopt(curl, CURLOPT_PASSWORD, params->secret);
+    }
+
+    /* Client certificate */
+    if (params->clientcert != NULL && params->clientkey != NULL) {
+        res |= curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
+        res |= curl_easy_setopt(curl, CURLOPT_SSLCERT, params->clientcert);
+
+        res |= curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
+        res |= curl_easy_setopt(curl, CURLOPT_SSLKEY, params->clientkey);
+    }
+
+    if (params->cacert != NULL) {
+        res |= curl_easy_setopt(curl, CURLOPT_CAINFO, params->cacert);
+    }
+
+    if (params->sslversion != CURL_SSLVERSION_DEFAULT) {
+        res |= curl_easy_setopt(curl, CURLOPT_SSLVERSION, (long) params->sslversion);
+    }
+
+    if (params->ciphersuites != NULL) {
+        res |= curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, params->ciphersuites);
     }
     }
 
 
+    res |= curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, (long) params->verify_peer);
+    res |= curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, (long) params->verify_host?2:0);
 
 
     res |= curl_easy_setopt(curl, CURLOPT_NOSIGNAL, (long) 1);
     res |= curl_easy_setopt(curl, CURLOPT_NOSIGNAL, (long) 1);
-    res |= curl_easy_setopt(curl, CURLOPT_TIMEOUT, (long) timeout);
-    res |= curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, (long) http_follow_redirect);
+    res |= curl_easy_setopt(curl, CURLOPT_TIMEOUT, (long) params->timeout);
+    res |= curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, (long) params->http_follow_redirect);
 
 
 
 
     res |= curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_function);
     res |= curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_function);
@@ -201,16 +241,16 @@ static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst, const
 
 
 	if (download_size > 0) {
 	if (download_size > 0) {
 
 
-	if (oneline) {
+	if (params->oneline) {
 		/* search for line feed */
 		/* search for line feed */
 		at = memchr(stream.buf, (char)10, download_size);
 		at = memchr(stream.buf, (char)10, download_size);
 		datasize = (double) (at - stream.buf);
 		datasize = (double) (at - stream.buf);
 		LM_DBG("  -- curl download size cut to first line: %d \n", (int) datasize);
 		LM_DBG("  -- curl download size cut to first line: %d \n", (int) datasize);
 	}
 	}
 	if (at == NULL) {
 	if (at == NULL) {
-		if (maxdatasize && ((unsigned int) download_size) > maxdatasize) {
+		if (params->maxdatasize && ((unsigned int) download_size) > params->maxdatasize) {
 			/* Limit at maximum data size */
 			/* Limit at maximum data size */
-			datasize = (double) maxdatasize;
+			datasize = (double) params->maxdatasize;
 			LM_DBG("  -- curl download size cut to maxdatasize : %d \n", (int) datasize);
 			LM_DBG("  -- curl download size cut to maxdatasize : %d \n", (int) datasize);
 		} else {
 		} else {
 			/* Limit at actual downloaded data size */
 			/* Limit at actual downloaded data size */
@@ -250,9 +290,8 @@ int curl_con_query_url(struct sip_msg* _m, const str *connection, const str* url
 {
 {
 	curl_con_t *conn = NULL;
 	curl_con_t *conn = NULL;
 	char *urlbuf = NULL;
 	char *urlbuf = NULL;
-	char *username_str = NULL;
-	char *password_str = NULL;
 	char *postdata = NULL;
 	char *postdata = NULL;
+	curl_query_t query_params;
 
 
 	unsigned int maxdatasize = default_maxdatasize;
 	unsigned int maxdatasize = default_maxdatasize;
 	int res;
 	int res;
@@ -269,14 +308,6 @@ int curl_con_query_url(struct sip_msg* _m, const str *connection, const str* url
 		return -1;
 		return -1;
 	}
 	}
 	LM_DBG("******** CURL Connection found %.*s\n", connection->len, connection->s);
 	LM_DBG("******** CURL Connection found %.*s\n", connection->len, connection->s);
-	if (conn->username.s != NULL && conn->username.len > 0)
-	{
-		username_str = as_asciiz(&conn->username);
-	}
-	if (conn->password.s != NULL && conn->password.len > 0)
-	{
-		password_str = as_asciiz(&conn->password);
-	}
 	maxdatasize = conn->maxdatasize;
 	maxdatasize = conn->maxdatasize;
 
 
 
 
@@ -319,20 +350,30 @@ int curl_con_query_url(struct sip_msg* _m, const str *connection, const str* url
 		LM_DBG("***** #### ***** CURL POST data: %s Content-type %s\n", postdata, contenttype);
 		LM_DBG("***** #### ***** CURL POST data: %s Content-type %s\n", postdata, contenttype);
 	}
 	}
 
 
-	res = curL_query_url(_m, urlbuf, result, username_str, password_str, (contenttype ? contenttype : "text/plain"), postdata,
-		conn->timeout, conn->http_follow_redirect, 0, (unsigned int) maxdatasize );
+	memset(&query_params, 0, sizeof(curl_query_t));
+	query_params.username = conn->username;
+	query_params.secret = conn->password;
+	query_params.contenttype = contenttype ? (char*)contenttype : "text/plain";
+	query_params.post = postdata;
+	query_params.clientcert = conn->clientcert;
+	query_params.clientkey = conn->clientkey;
+	query_params.cacert = default_tls_cacert;
+	query_params.ciphersuites = conn->ciphersuites;
+	query_params.sslversion = conn->sslversion;
+	query_params.verify_peer = conn->verify_peer;
+	query_params.verify_host = conn->verify_host;
+	query_params.timeout = conn->timeout;
+	query_params.http_follow_redirect = conn->http_follow_redirect;
+	query_params.oneline = 0;
+	query_params.maxdatasize = maxdatasize;
+
+	res = curL_query_url(_m, urlbuf, result, &query_params);
 
 
 	LM_DBG("***** #### ***** CURL DONE : %s \n", urlbuf);
 	LM_DBG("***** #### ***** CURL DONE : %s \n", urlbuf);
 error:
 error:
 	if (urlbuf != NULL) {
 	if (urlbuf != NULL) {
 		pkg_free(urlbuf);
 		pkg_free(urlbuf);
 	}
 	}
-	if (username_str != NULL) {
-		pkg_free(username_str);
-	}
-	if (password_str != NULL) {
-		pkg_free(password_str);
-	}
 	if (postdata != NULL) {
 	if (postdata != NULL) {
 		pkg_free(postdata);
 		pkg_free(postdata);
 	}
 	}
@@ -348,8 +389,26 @@ error:
 int http_query(struct sip_msg* _m, char* _url, str* _dst, char* _post)
 int http_query(struct sip_msg* _m, char* _url, str* _dst, char* _post)
 {
 {
 	int res;
 	int res;
-
-	res =  curL_query_url(_m, _url, _dst, NULL, NULL, "text/plain", _post, default_connection_timeout, default_http_follow_redirect, 1, 0);
+	curl_query_t query_params;
+
+	memset(&query_params, 0, sizeof(curl_query_t));
+	query_params.username = NULL;
+	query_params.secret = NULL;
+	query_params.contenttype = "text/plain";
+	query_params.post = _post;
+	query_params.clientcert = NULL;
+	query_params.clientkey = NULL;
+	query_params.cacert = NULL;
+	query_params.ciphersuites = NULL;
+	query_params.sslversion = default_tls_version;
+	query_params.verify_peer = default_tls_verify_peer;
+	query_params.verify_host = default_tls_verify_host;
+	query_params.timeout = default_connection_timeout;
+	query_params.http_follow_redirect = default_http_follow_redirect;
+	query_params.oneline = 1;
+	query_params.maxdatasize = 0;
+
+	res =  curL_query_url(_m, _url, _dst, &query_params);
 
 
 	return res;
 	return res;
 }
 }