Saturday, December 17. 2011
Client Certificates In PHP / Oracle Iplanet Web Server
These days I have been working in a customer with the same issue which was discussing in the last series of this blog: client certificate login (custom solution). The big difference here was that this customer is working with PHP (last version 5.3) and Oracle Iplanet Web Server 7.0 (formerly Sun Java System Web Server, formerly Sun ONE Web Server, formerly Iplanet Web Server and now included in Oracle Fusion Middleware WebTier). This web server is the last version of the Sun web server which comes from the time of Sun and Netscape alliance. It is curious how just when I decided to publish the series this topic has come out to me again and again.
PHP when is integrated with Apache (the most common situation) uses some environment variables (SSL_CLIENT_CERT, SSL_CLIENT_S_DN and so on) that mod_ssl (module for Apache Web Server to get SSL communication -HTTPS- which relies on OpenSSL) provides to PHP in $_SERVER array. These vars contain some info about the SSL communication in general and the client certificate in particular, some of them are different parts or fields of the cert and SSL_CLIENT_CERT is the whole certificate, PEM format (see StdEnvVars option in the documentation for further info). As always the developer team has its way environment, windows + Apache 2.2 + PHP 5.2, while the pre and production environment of the customer is Solaris 10 + Iplanet 7.0 + PHP 5.3. Obviously the application did not work when it was tested in pre-production (what a strange thing!). The variables that mod_ssl should inject were not there, which was really confusing for the developers, of course the fact that the web server was an Iplanet and not an Apache did not matter much to them.
When PHP is compiled against the Iplanet Web Server it uses old NSAPI (Netscape Server Application Programming Interface) to interact with the http daemon. Typical PHP compilation (very short in modules) for this environment is like this:
./configure --prefix=/opt/php-5.3 --with-nsapi=/opt/SUNWwbsvr7 \ --enable-ftp --with-pear --enable-pdo --with-openssl
The /opt/SUNWwbsvr7 directory is where the Iplanet Web Server is installed, the installtion needs sample applications component because include files are in there. Then you need to configure some files to make the web server process PHP files (see this wiki page for compilation and configuration details).
If you check the NSAPI developer guide, the client certificate is placed as a request variable named auth-cert. This var contains the certificate in DER format but encoded into text with BASE64. The nsapi.c file in PHP source registers this variable in its own environment with another name CLIENT_CERT. So you can access the certificate (DER + BASE64) like this $_SERVER['CLIENT_CERT']. Then the certificate can be parsed using some PHP/SSL methods. This sample PHP file performs exactly what I said.
<?php // header to plain/text header("content-type: text/plain"); // print server vars print("SERVER vars:\n"); print_r($_SERVER); // get the headers print("\n\nHEADERS:\n"); print_r(getallheaders()); // print certificate parsed by SSL $pem = "-----BEGIN CERTIFICATE-----\n" . $_SERVER['CLIENT_CERT'] . "\n-----END CERTIFICATE-----\n"; $cert = openssl_x509_parse($pem); print("\n\nCertificate parsed by OpenSSL:\n"); print_r($cert); // print some variables from the cert print("\n\nGetting some data from the parsed cert:\n"); print("name: " . $cert['name'] . "\n"); print("subject->CN: " . $cert['subject']['CN'] . "\n"); print("validFrom: " . $cert['validFrom'] . "\n"); ?>
As you see the server variable is converted into SSL PEM format (as the certificate is already in BASE64, setting the header and footer line is the only step to transform it into PEM) and then it is parsed and stored into an array by openssl_x509_parse function. With this array any field of the certificate can be retrieved easily.
When finally the application went to production I realized that the PHP web server was behind a proxy (another difference, this time an architectural one). In this case the certificate is not received in the commented way, in this architecture all the SSL stuff (certificate exchange process included) is managed by the proxy and the client certificate is usually forwarded to the backend server using a header (proxy-auth-cert in case of iPlanet Web Proxy Server). In this solution getallheaders PHP function should be used to get the certificate from the specified header and construct the PEM variable exactly in the same way I did in the previous example.
So with PHP and Oracle Iplanet Web Server (any NSAPI server in general although I do not know anyone else) you obviously cannot use mod_ssl/Apache environment variables, there is another one called CLIENT_CERT which is the certificate itself in DER + BASE64 (behind a proxy the certificate is usually placed in a header). Once this fact is known it is easy to find a way of getting any certificate field with PHP code (I used a PHP/SSL function to parse the certificate into an array of variables). Please if you are a developer, do not start coding before all the versions, software stack and architecture are perfectly defined, you usually will work twice or even more (and you will drive a lot of people crazy too, people like me).
Never lose hope!
Sunday, December 11. 2011
Zuma's Revenge!
This week I was on vacation. I was on the mood of doing nothing, so I decided to play some PC game. I had very good references of the Zuma Blitz that people play in Facebook. Besides I had played before Plants vs Zombies of the same company (PopCap games). This one was fantastic. So finally I decided to play Zuma's Revenge! (PC version of the Facebook one).
It has been horrible, sometimes I forget how obsessive I am. I quickly got the last level (level 60), just in one game but I died in that stage. The problem is that, when you die, you do not start in the same stage but five levels before (and with only two lifes!). Maybe I am too clumsy, but it was absolutely impossible for me. I played long hours and the best I did was reaching level 60, I did not even fight against the final boss. I realized I had a problem when I dreamt with the damned balls. So today I had only one mission, finishing the game at all cost (I mean, of course, cheating). Finally I got a cheat to slow down the balls (I would have preferred infinite lifes but I just needed to fool myself). Finally I beat the final boss.
So now it is over. The situation makes me not to trust anymore on PopCap games, I want smooth games, never like this one in which you have to be the fucking hawkeye to reach the final.
You are advised!PS: Of course both games (Zuma and Plants vs Zombies) work in Linux under wine.
Comments