PHP, OAuth and the LinkedIn API with SSL on Windows 7

I have been developing a tool which integrates a LinkedIn profile into WordPress. That’s not complicated because LinkedIn has an API which enables access to a LinkedIn users’ data. This API has great documentation and examples, which invites you to give it a try.

The same does not apply to the OAuth extension for PHP but you’ll be able to use it, especially when used with a good example.

I have two development systems: the first is a Windows 7, the second is a virtual host on Linux. I used this OAuth library on Windows 7. I ran into this exception while experimenting:

[28-Mar-2012 10:08:24 UTC] PHP Fatal error:  Uncaught exception 'OAuthException' with message 'making the request failed (Peer certificate cannot be authenticated with known CA certificates)' in ...\wp-content\plugins\bastb-plugin.php:33
Stack trace:
#0 ...\wp-content\plugins\bastb-plugin.php(33): OAuth->getRequestToken('https://api.lin...')
#1 ...\wp-settings.php(196): include_once('...')
#2 ...\wp-config.php(90): require_once('...')
#3 ...\wp-load.php(29): require_once('...')
#4 ...\wordpress\wp-blog-header.php(12): require_once('...')
#5 ...\index.php(17): require('... ...')
#6 {main}
  thrown in ...\wp-content\plugins\bastb-plugin.php on line 33

Running the code on the Linux host did not reveal that problem.

OAuth, or better yet: cURL, does not trust any Certificate Authority at all. Documentation on the cURL website describing the problem, and options to resolve the problem. Step 3 applies and make sure you pay attention to the openssl s_client step, as there’s one thing you can easily overlook:

D:\Program Files (x86)\zendserverce\Apache2\bin>openssl s_client -connect api.linkedin.com:443
Loading 'screen' into random state - done
CONNECTED(000001B8)
depth=2 /C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
 0 s:/C=US/ST=California/L=Mountain View/O=LinkedIn Corporation/OU=Production Operations Group/CN=api.linkedin.com
   i:/C=US/O=Thawte, Inc./CN=Thawte SGC CA - G2
 1 s:/C=US/O=Thawte, Inc./CN=Thawte SGC CA - G2
   i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc.
 - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5
 2 s:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc.
 - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5
   i:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
---
Server certificate
<remaining output removed>

You need the root CA certificate, the one with subject C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority. This one doesn’t show up when you view the certificates using Chrome or Internet Explorer on Windows. You get it from this page, and, for LinkedIn, you’ll need the certificate for VeriSign Class 3 Public Primary CA. Save the VeriSign Class 3 Public Primary CA certificate in a ca-bundle file named api.linkedin.pem, make sure OAuth actually uses cURL and make OAuth use the ca-bundle:

$oauth = new OAuth($token, $secret);
$pem = dirname(__FILE__) . "/api.linkedin.pem");
$oauth->setRequestEngine(OAUTH_REQENGINE_CURL);
$oauth->setCAPath(null, $pem);

If you happen to search for logging, it’s in ZendServer\logs\php_error.log when using ZendServer Community Edition.

Comments, feedback, improvements are much appreciated.

Leave a Reply

Your email address will not be published. Required fields are marked *