Skip to content

Commit

Permalink
curl: Implement additional TLS parameters
Browse files Browse the repository at this point in the history
- Add per-connection useragent param
- Add sslversion modparam
- Add per-connection sslversion param
- Add per-connection client cert/key/ciphers
- Ensure all strings are null-terminated for libcurl
  • Loading branch information
Hugh Waite committed Jan 21, 2016
1 parent 64764ff commit eb067dd
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 62 deletions.
17 changes: 11 additions & 6 deletions modules/curl/curl.c
Expand Up @@ -74,15 +74,16 @@ MODULE_VERSION
/* Module parameter variables */
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_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 */
char *default_cipher_suite_list = NULL; /*!< List of allowed cipher suites */
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 */
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 */
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 */

static curl_version_info_data *curl_info;
Expand Down Expand Up @@ -142,6 +143,7 @@ static param_export_t params[] = {
{"tlsclientcert", PARAM_STRING, &default_tls_clientcert },
{"tlsclientkey", PARAM_STRING, &default_tls_clientkey },
{"tlscipherlist", PARAM_STRING, &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 },
Expand Down Expand Up @@ -246,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: 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: 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: 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("Extra: Curl supports %s %s %s \n",
Expand Down
27 changes: 15 additions & 12 deletions modules/curl/curl.h
Expand Up @@ -37,15 +37,16 @@

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_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 char *default_cipher_suite_list; /*!< List of allowed cipher suites */
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 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 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 counter_handle_t connections; /* Number of connection definitions */
Expand All @@ -68,15 +69,17 @@ typedef struct _curl_con
unsigned int conid; /*!< Connection ID */
str url; /*!< The URL without schema (host + base URL)*/
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 useragent; /*!< Useragent to use for this connection */
str cacert; /*!< File name of CA cert to use */
str clientcert; /*!< File name of CA client cert */
str clientkey; /*!< File name of CA client key */
int verify_peer; /*!< TRUE if server cert to be verified */
int verify_host; /*!< TRUE if server CN/SAN 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 */
unsigned int port; /*!< The port to connect to */
int timeout; /*!< Timeout for this connection */
Expand Down
67 changes: 47 additions & 20 deletions modules/curl/curlcon.c
Expand Up @@ -26,6 +26,8 @@
* \ingroup curl
*/

#include <curl/curl.h>

#include "../../hashes.h"
#include "../../dprint.h"
#include "../../parser/parse_param.h"
Expand Down Expand Up @@ -110,24 +112,24 @@ int curl_parse_param(char *val)
str params = STR_NULL;
str failover = STR_NULL;

str client_cert = { default_tls_clientcert, default_tls_clientcert ? strlen(default_tls_clientcert) : 0 };
str client_key = { default_tls_clientkey, default_tls_clientkey ? strlen(default_tls_clientkey) : 0 };
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 timeout = default_connection_timeout;
str useragent = { default_useragent, strlen(default_useragent) };
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;
char *p;
char *u;
param_t *conparams = NULL;
curl_con_t *cc;

username.len = 0;
password.len = 0;
LM_INFO("curl modparam parsing starting\n");
LM_DBG("modparam curlcon: %s\n", val);

Expand Down Expand Up @@ -307,7 +309,7 @@ int curl_parse_param(char *val)
maxdatasize = default_maxdatasize;
}
LM_DBG("curl [%.*s] - timeout [%d]\n", pit->name.len, pit->name.s, maxdatasize);
} else if(pit->name.len==12 && strncmp(pit->name.s, "verifypeer", 7)==0) {
} 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);
Expand All @@ -318,7 +320,7 @@ int curl_parse_param(char *val)
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==12 && strncmp(pit->name.s, "verifyhost", 7)==0) {
} 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);
Expand All @@ -329,6 +331,29 @@ int curl_parse_param(char *val)
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 {
LM_ERR("curl Unknown parameter [%.*s] \n", pit->name.len, pit->name.s);
}
Expand All @@ -337,14 +362,6 @@ int curl_parse_param(char *val)

/* 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);
LM_DBG("cname: [%.*s] client_cert [%.*s] client_key [%.*s] verify_peer [%d] verify_host [%d]\n",
name.len, name.s, client_cert.len, client_cert.s, client_key.len, client_key.s,
verify_peer, verify_host);

if(conparams != NULL) {
free_params(conparams);
}
Expand All @@ -353,19 +370,29 @@ int curl_parse_param(char *val)
if (cc == NULL) {
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->failover = failover;
cc->useragent = useragent;
cc->useragent = as_asciiz(&useragent);
cc->url = url;
cc->clientcert = client_cert;
cc->clientkey = client_key;
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->maxdatasize = maxdatasize;
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;

error:
Expand Down
36 changes: 12 additions & 24 deletions modules/curl/functions.c
Expand Up @@ -55,6 +55,7 @@ typedef struct {
char *clientkey;
char *cacert;
char *ciphersuites;
unsigned int sslversion;
unsigned int verify_peer;
unsigned int verify_host;
unsigned int timeout;
Expand Down Expand Up @@ -160,7 +161,6 @@ static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst, const

/* Client certificate */
if (params->clientcert != NULL && params->clientkey != NULL) {
LM_ERR("Setting curl cert %s key %s \n", params->clientcert, params->clientkey);
res |= curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
res |= curl_easy_setopt(curl, CURLOPT_SSLCERT, params->clientcert);

Expand All @@ -169,12 +169,14 @@ static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst, const
}

if (params->cacert != NULL) {
LM_ERR("Setting ca cert %s\n", params->cacert);
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) {
LM_ERR("Setting ciphersuites %s\n", params->ciphersuites);
res |= curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, params->ciphersuites);
}

Expand Down Expand Up @@ -288,8 +290,6 @@ int curl_con_query_url(struct sip_msg* _m, const str *connection, const str* url
{
curl_con_t *conn = NULL;
char *urlbuf = NULL;
char *username_str = NULL;
char *password_str = NULL;
char *postdata = NULL;
curl_query_t query_params;

Expand All @@ -308,14 +308,6 @@ int curl_con_query_url(struct sip_msg* _m, const str *connection, const str* url
return -1;
}
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;


Expand Down Expand Up @@ -359,14 +351,15 @@ int curl_con_query_url(struct sip_msg* _m, const str *connection, const str* url
}

memset(&query_params, 0, sizeof(curl_query_t));
query_params.username = username_str;
query_params.secret = password_str;
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.s;
query_params.clientkey = conn->clientkey.s;
query_params.clientcert = conn->clientcert;
query_params.clientkey = conn->clientkey;
query_params.cacert = default_tls_cacert;
query_params.ciphersuites = default_cipher_suite_list;
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;
Expand All @@ -381,12 +374,6 @@ int curl_con_query_url(struct sip_msg* _m, const str *connection, const str* url
if (urlbuf != NULL) {
pkg_free(urlbuf);
}
if (username_str != NULL) {
pkg_free(username_str);
}
if (password_str != NULL) {
pkg_free(password_str);
}
if (postdata != NULL) {
pkg_free(postdata);
}
Expand All @@ -413,6 +400,7 @@ int http_query(struct sip_msg* _m, char* _url, str* _dst, char* _post)
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;
Expand Down

0 comments on commit eb067dd

Please sign in to comment.