<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>unitstep.net &#187; curl</title>
	<atom:link href="http://unitstep.net/blog/category/curl/feed/" rel="self" type="application/rss+xml" />
	<link>http://unitstep.net</link>
	<description>the home of peter chng</description>
	<lastBuildDate>Mon, 06 Feb 2012 01:23:17 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Using cURL in PHP to access HTTPS (SSL/TLS) protected sites</title>
		<link>http://unitstep.net/blog/2009/05/05/using-curl-in-php-to-access-https-ssltls-protected-sites/</link>
		<comments>http://unitstep.net/blog/2009/05/05/using-curl-in-php-to-access-https-ssltls-protected-sites/#comments</comments>
		<pubDate>Wed, 06 May 2009 01:22:12 +0000</pubDate>
		<dc:creator>Peter Chng</dc:creator>
				<category><![CDATA[curl]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[pki]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[https]]></category>
		<category><![CDATA[ssl]]></category>
		<category><![CDATA[tls]]></category>

		<guid isPermaLink="false">http://unitstep.net/?p=877</guid>
		<description><![CDATA[From PHP, you can access the useful cURL Library (libcurl) to make requests to URLs using a variety of protocols such as HTTP, FTP, LDAP and even Gopher. (If you&#8217;ve spent time on the *nix command line, most environments also have the curl command available that uses the libcurl library) In practice, however, the most [...]]]></description>
			<content:encoded><![CDATA[<p class="image align-right"><img src="http://unitstep.net/wordpress/wp-content/uploads/2009/05/curl-https-padlock.jpg" alt="curl-https-padlock" title="curl-https-padlock" width="100" height="116" class="alignnone size-full wp-image-895" /></p>
<p>From <acronym class="uttInitialism" title="PHP: Hypertext Preprocessor">PHP</acronym>, you can access the useful <a href="http://ca2.php.net/manual/en/book.curl.php">cURL Library (libcurl)</a> to make requests to URLs using a variety of protocols such as <acronym class="uttInitialism" title="HyperText Transfer Protocol">HTTP</acronym>, FTP, LDAP and even <a href="http://blog.delicious.com/blog/2009/04/delicious-now-supports-gopher.html">Gopher</a>.  (If you&#8217;ve spent time on the *nix command line, most environments also have the <code>curl</code> command available that uses the libcurl library)</p>
<p>In practice, however, the most commonly-used protocol tends to be <acronym class="uttInitialism" title="HyperText Transfer Protocol">HTTP</acronym>, especially when using <acronym class="uttInitialism" title="PHP: Hypertext Preprocessor">PHP</acronym> for server-to-server communication.  Typically this involves accessing another web server as part of a web service call, using some method such as <a href="http://www.w3.org/XML/" class="ubernym uttInitialism"><acronym class="uttInitialism" title="eXtensible Markup Language">XML</acronym></a>-RPC or REST to query a resource.  For example, <a href="http://delicious.com/">Delicious</a> offers <a href="http://delicious.com/help/api">a <acronym class="uttInitialism" title="HyperText Transfer Protocol">HTTP</acronym>-based API</a> to manipulate and read a user&#8217;s posts.  However, when trying to access a HTTPS resource (such as the delicious API), there&#8217;s a little more configuration you have to do before you can get cURL working right in <acronym class="uttInitialism" title="PHP: Hypertext Preprocessor">PHP</acronym>.</p>
<h2>The problem</h2>
<p>If you simply try to access a HTTPS (SSL or TLS-protected resource) in <acronym class="uttInitialism" title="PHP: Hypertext Preprocessor">PHP</acronym> using cURL, you&#8217;re likely to run into some difficulty.  Say you have the following code: (Error handling omitted for brevity)</p>
<pre><code>// Initialize session and set <acronym class="uttInitialism" title="Uniform Resource Locator">URL</acronym>.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);

// Set so curl_exec returns the result instead of outputting it.
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

// Get the response and close the channel.
$response = curl_exec($ch);
curl_close($ch);</code></pre>
<p>If <code>$url</code> points toward an HTTPS resource, you&#8217;re likely to encounter an error like the one below:</p>
<pre><code>Failed: Error Number: 60. Reason: SSL certificate problem, verify that the CA cert is OK. Details:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed</code></pre>
<p>The problem is that cURL has not been configured to trust the server&#8217;s HTTPS certificate.  The concepts of certificates and PKI revolves around the trust of Certificate Authorities (CAs), and by default, cURL is setup to <strong>not trust any CAs</strong>, thus it won&#8217;t trust any web server&#8217;s certificate.  So why don&#8217;t you have problems visiting HTTPs sites through your web browser? As it happens, the browser developers were nice enough to <a href="/blog/2009/03/16/using-the-basic-constraints-extension-in-x509-v3-certificates-for-intermediate-cas/">include a list of default CAs to trust</a>, covering most situations, so as long as the website operator purchased a certificate from one of these CAs.</p>
<h2>The quick fix</h2>
<p>There are two ways to solve this problem.  Firstly, we can simply configure cURL to accept <strong>any server(peer) certificate</strong>.  This isn&#8217;t optimal from a security point of view, but if you&#8217;re not passing sensitive information back and forth, this is probably alright.  Simply add the following line before calling <code>curl_exec()</code>:</p>
<pre><code>curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);</code></pre>
<p>This basically causes cURL to blindly accept any server certificate, without doing any verification as to which CA signed it, and whether or not that CA is trusted.  If you&#8217;re at all concerned about the data you&#8217;re passing to or receiving from the server, you&#8217;ll want to enable this peer verification properly.  Doing so is a bit more complicated.</p>
<h2>The proper fix</h2>
<p>The proper fix involves setting the <code>CURLOPT_CAINFO</code> parameter.  This is used to point towards a CA certificate that cURL should trust.  Thus, any server/peer certificates issued by this CA will also be trusted.  In order to do this, we first need to get the CA certificate.  In this example, I&#8217;ll be using the <a href="https://api.del.icio.us/">https://api.del.icio.us/</a> server as a reference.</p>
<p>First, you&#8217;ll need to visit the <acronym class="uttInitialism" title="Uniform Resource Locator">URL</acronym> with your web browser in order to grab the CA certificate.  Then, (in Firefox) open up the security details for the site by double-clicking on the padlock icon in the lower right corner:</p>
<p class="image">
<img src="http://unitstep.net/wordpress/wp-content/uploads/2009/05/curl-https-1.jpg" alt="curl-https-1" title="curl-https-1" width="263" height="84" class="alignnone size-full wp-image-891" />
</p>
<p>Then click on &#8220;View Certificate&#8221;:</p>
<p class="image">
<a href="http://unitstep.net/wordpress/wp-content/uploads/2009/05/curl-https-2.jpg"><img src="http://unitstep.net/wordpress/wp-content/uploads/2009/05/curl-https-2-300x250.jpg" alt="curl-https-2" title="curl-https-2" width="300" height="250" class="alignnone size-medium wp-image-890" /></a>
</p>
<p>Bring up the &#8220;Details&#8221; tab of the cerficates page, and <strong>select the certificate at the top of the hierarchy</strong>.  This is the CA certificate.</p>
<p class="image">
<a href="http://unitstep.net/wordpress/wp-content/uploads/2009/05/curl-https-3.jpg"><img src="http://unitstep.net/wordpress/wp-content/uploads/2009/05/curl-https-3-255x300.jpg" alt="curl-https-3" title="curl-https-3" width="255" height="300" class="alignnone size-medium wp-image-892" /></a>
</p>
<p>Then click &#8220;Export&#8221;, and save the CA certificate to your selected location, making sure to select the <strong>X.509 Certificate (PEM)</strong> as the save type/format.</p>
<p class="image">
<a href="http://unitstep.net/wordpress/wp-content/uploads/2009/05/curl-https-4.jpg"><img src="http://unitstep.net/wordpress/wp-content/uploads/2009/05/curl-https-4-300x223.jpg" alt="curl-https-4" title="curl-https-4" width="300" height="223" class="alignnone size-medium wp-image-893" /></a>
</p>
<p>Now we need to modify the cURL setup to use this CA certificate, with <code>CURLOPT_CAINFO</code> set to point to where we saved the CA certificate file to.</p>
<pre><code>curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_CAINFO, getcwd() . "/CAcerts/BuiltinObjectToken-EquifaxSecureCA.crt");</code></pre>
<p>The other option I&#8217;ve included, <code>CURLOPT_SSL_VERIFYHOST</code> can be set to the following integer values:</p>
<ul>
<li>0: Don&#8217;t check the common name (CN) attribute</li>
<li>1: Check that the common name attribute at least exists</li>
<li>2: Check that the common name exists and that it matches the host name of the server</li>
</ul>
<p>If you have <code>CURLOPT_SSL_VERIFYPEER</code> set to false, then from a security perspective, it doesn&#8217;t really matter what you&#8217;ve set <code>CURLOPT_SSL_VERIFYHOST</code> to, since without peer certificate verification, the server could use any certificate, including a self-signed one that was guaranteed to have a CN that matched the server&#8217;s host name.  So this setting is really only relevant if you&#8217;ve enabled certificate verification.</p>
<p>This ensures that not just any server certificate will be trusted by your cURL session.  For example, if an attacker were to somehow redirect traffic from <strong>api.delicious.com</strong> to their own server, the cURL session here would not properly initialize, since the attacker would not have access to a server certificate (i.e. would not have the private key) trusted by the CA we added.  These steps effectively export the trusted CA from the web browser to the cURL configuration.</p>
<h2>More information</h2>
<p>If you have the CA certificate, but it is not in the PEM format (i.e. it is in a binary or DER format that isn&#8217;t Base64-encoded), you&#8217;ll need to use something like OpenSSL to convert it to the PEM format.  The exact command differs depending on whether you&#8217;re converting from PKCS12 or DER format.</p>
<p>There is a <code>CURLOPT_CAPATH</code> option that allows you to specify a directory that holds multiple CA certificates to trust.  But it&#8217;s not as simple as dumping every single CA certificate in this directory.  Instead, they CA certificates must be named properly, and the <a href="http://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html">OpenSSL <code>c_rehash</code> utility can be used</a> to properly setup this directory for use by cURL.</p>
<hr/>Copyright &copy; 2012 <strong><a href="http://unitstep.net">unitstep.net</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement. Please contact <strong><a href="mailto:webmaster@unitstep.net">webmaster@unitstep.net</a></strong> for more information.<br/><span style="float: right;font-size: 7pt"><a href="http://blog.taragana.com/index.php/archive/wordpress-plugins-provided-by-taraganacom/">Plugin</a> by <a href="http://www.taragana.com/">Taragana</a></span>]]></content:encoded>
			<wfw:commentRss>http://unitstep.net/blog/2009/05/05/using-curl-in-php-to-access-https-ssltls-protected-sites/feed/</wfw:commentRss>
		<slash:comments>101</slash:comments>
		</item>
	</channel>
</rss>

