Freeswitch

Modifying Freeswitch’s XML interfaces to support custom SSL client + server certificates

Posted in Freeswitch on June 19th, 2009 by ententecorp – Be the first to comment

As you can see from the previous post, there was a lot of work left to be done in order to secure communications between Freeswitch’s XML interfaces and our web servers. I researched the other possible security options with libcurl using https, as well as SSL encryption options in general. Libcurl already supported a bunch of different SSL certificate options that were not being used in Freeswitch, presumably because nobody had ever cared enough to implement them before.

It seemed that the most secure setup possible was to implement client & server SSL certificate authentication (both ends check each other’s certs). I used this resource as an introduction to Client Authentication with SSL. This guide also explained how to become your own certificate authority and sign your own client + server certificates. Becoming our own CA is perfect for our setup because, unlike a browser scenario, libcurl wouldn’t be popping up a message telling our users that we are an untrusted/unofficial CA.

The first thing to do was to modify Freeswitch to support the various SSL options that libcurl provides. It wasn’t actually very difficult to accomplish this. Mod_xml_curl is a concise piece of code (~450 lines) so I studied it over for a while to figure out how the existing options were set using the XML config.

I changed the option ‘ignore-cacert-check’ to ‘enable-cacert-check’. Since the checks were already disabled by default in the module, I am not changing the default behavior and instead providing an option for those who want that extra security. When this new option is set to true, libcurl will check to make sure that the web server’s certificate is authorized by one of the big public CAs (or whichever CA cert we supply it manually). I also added the following options to mod_xml_curl:

  1. ’ssl-cert-path’ provides the path of the client’s public SSL certificate, which it sends to the web server during the handshake.
  2. ’ssl-key-path’ gives the path of the client’s private SSL key, which it uses to decode information coming back from the web server (must be kept PRIVATE!).
  3. ’ssl-key-password’ gives the plaintext password of the client’s private SSL key that was chosen when the key was generated. In this case, the password doesn’t provide much extra security since if an intruder can access the private key file they can also access the password now stored in your Freeswitch config files.
  4. ’ssl-version’ is an optional parameter that allows you to specify which verison of the SSL protocol must be used during communication. Accepted values are ‘SSLv3′ and ‘TLSv1′. Version 2 of SSL is not secure and is disabled by default in libcurl. Not setting this option will allow either SSLv3 or TLSv1 to be used.
  5. ’ssl-cacert-file’ should give the path of a file containing the web server’s CA certificate and is only required if you are acting as your own CA instead of paying for one of the public CAs.
  6. ‘enable-ssl-verifyhost’ should be set to true to override the default behavior of mod_xml_curl, which is to ignore whether or not the hostname on the server’s cert matches the hostname of the server.

I’ve submitted patches for both mod_xml_curl and mod_xml_cdr to implement these changes, so hopefully you’ll see them show up in an upcoming build of Freeswitch!

I may cover implementation of these details on a Ruby webserver in the future, but for now you should reference the following article: SSL Client Certificate Authentication in Ruby on Rails

Analyzing the Security of Freeswitch’s XML Curl Interfaces

Posted in Freeswitch on June 18th, 2009 by ententecorp – Be the first to comment

Recently, we were working on a part of our Freeswitch configuration web app. This app generates configuration files for our servers in XML format. When Freeswitch needs a piece of configuration data, it is able to fetch the configurations in real time from our web server using its ‘mod_xml_curl’ module. This is a very powerful tool, but as we were thinking about how to deploy this to a large number of our client servers, security came to mind.

Freeswitch’s XML interfaces have the ability to provide authentication credentials to a web server using HTTP Basic authentication, which essentially transmits the username and password as plain text (yeah, ok, it’s base64 encoded, but that may as well be plain text). To offset this potential security issue and prevent unauthorized individuals from requesting our server configs, Freeswitch can connect to a web server through SSL (https). This is a little bit better, but there were a few things lacking from this solution.

For one, there was no ability for us to use anything other than an official Certificate Authority-issued SSL certificate (i.e. Verisign or Godaddy). Or at least that’s what the Freeswitch docs said, more on that later. Anyway, those certificates cost money, and during the development phase I’d consider it to be an unnecessary expense.

In order to get around the need to verify the server’s SSL certificate with a CA, there was an option in xml_curl.conf.xml called ‘ignore-cacert-check’. This was supposed to tell Freeswitch to not even bother checking whether the web server’s certificate was valid or not. Not a great solution, because this opens up the potential for a man in the middle attack where another web server intercepts communications with the Freeswitch server and pretends to be our official server. Once the Freeswitch server establishes a connection and sends out its plaintext username/password, the unauthorized web server now has the credentials and could use them to request configs from our server.

So it seemed to be an all-or-nothing choice: either pay for a licensed SSL certificate or forgo any real notion of security in the system. But as it turned out it didn’t even matter, because regardless of the ‘ignore-cacert-check’ variable, mod_xml_curl and mod_xml_cdr were already telling libcurl to skip peer verification and skip hostname validation (checking to see that the host is actually the one listed in the cert).

if (!strncasecmp(bindings->url, "https", 5)) {
	curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
	curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
}

So these options were being disabled no matter what when https was used. Obviously some changes were needed to enhance the security here.

More in the next post.