Category Archives: Apache

Frontend for openssl to check key chains

Since checking SSL key chains with openssl is sometimes a bit tricky, I have written a little perl script as wrapper around it.

Just download, unzip it and run it as follows:

./ -p server port

-p (optional) prints out the certificates as well
server is the server to check
port (optional) is the port to connect to.

Here is the code:

#!/usr/bin/perl -w

use strict;

my $has_date_parse = 1;
eval {
	require Date::Parse;
	Date::Parse->import( qw/str2time/ )

if ( $@ ne "" ) {
	print "Module Date::Parse not found! Skipping expiration date calculation!\n";
	$has_date_parse = 0;

my $print_cert = 0;
my $host = shift || &usage();
if ( $host eq '-p' ) {
	$print_cert = 1;
	$host = shift;
my $port = (shift || 443);

my $output = `echo "\t" | openssl s_client -host $host -port $port -showcerts 2> /dev/null`;

my $cert_num = 0;

my $line;
my @certs;
my %certs;

foreach $line ( split /\n/, $output ) {
	if ( $line =~ /BEGIN CERTIFICATE/ .. $line =~ /END CERTIFICATE/ ) {
		$certs[$cert_num] .=  "$line\n";
	$cert_num += 1 if $line =~ /END CERTIFICATE/;

my $i;
my $serial;
my $attribute;
foreach $i ( 0 .. scalar @certs -1 ) {
	$serial = qx{echo "$certs[$i]" | openssl x509 -serial -noout};
	$serial =~ s/serial=//;
	chomp $serial;
	$certs{$serial}{'certificate'} = $certs[$i];

	foreach $attribute ( qw/issuer subject issuer_hash subject_hash enddate/ ) {
		$certs{$serial}{"$attribute"} = qx{echo "$certs[$i]" | openssl x509 -$attribute -noout};
		chomp $certs{$serial}{"$attribute"};
		$certs{$serial}{"$attribute"} =~ s/notAfter=//;

	# Certificate stored, reuse @certs to keep order with serial number
	$certs[$i] = $serial;
	$certs{$serial}{"order"} = $i;

print "\nChecked server: $host on port $port\n";

my $found;
foreach $i ( 0 .. scalar @certs -1 ) {
	print "\nCertificate $i:\n";
	$serial = $certs[$i];
	print "\t", $certs{$serial}{"subject"}, " (hashed: ", $certs{$serial}{"subject_hash"}, ")\n";
	print "\tserial number (check in browser): $serial\n";
	print "\texpires: ", $certs{$serial}{"enddate"};
	if ( $has_date_parse == 1 ) {
		print " (in ", int ((str2time($certs{$serial}{"enddate"}) - time) /60/60/24  ), " days)" ;

	print "\n";
	print "\t", $certs{$serial}{"issuer"}, " (hashed: ", $certs{$serial}{"issuer_hash"}, ")\n";
	print "\tissuer found in chain: ";
	$found = "NO - should be root certificate";
	if ( $certs{$serial}{"issuer_hash"} eq $certs{$serial}{"subject_hash"} ) {
	} else {
		foreach ( keys %certs ) {
			if ( $certs{$serial}{"issuer_hash"} eq $certs{$_}{"subject_hash"} ) {
				$found = "YES";
	print "$found\n";

if ( $print_cert == 1 ) {
	foreach $i ( 0 .. scalar @certs -1 ) {
		print "\nCertificate $i:\n";
		$serial = $certs[$i];
		print $certs{$serial}{"certificate"}

sub usage {
	print "Usage: $0 [-p] server_name [port]\n";
	print "\t-p : also print certificates\n";
	print "\tserver_name : server to check, mandatory\n";
	print "\tport : port to check, default: 443\n";

Its output is as follows:

$ ./

Checked server: on port 443

Certificate 0:
	subject= /C=DE/OU=Domain Control Validated/ (hashed: dad54aee)
	serial number (check in browser): 11213FB18C3CEF8B39A731AB874D155363F2
	expires: Dec  8 11:13:28 2015 GMT (in 318 days)
	issuer= /C=BE/O=GlobalSign nv-sa/CN=GlobalSign Domain Validation CA - SHA256 - G2 (hashed: 79701ca5)
	issuer found in chain: YES

Certificate 1:
	subject= /C=BE/O=GlobalSign nv-sa/CN=GlobalSign Domain Validation CA - SHA256 - G2 (hashed: 79701ca5)
	serial number (check in browser): 040000000001444EF03E20
	expires: Feb 20 10:00:00 2024 GMT (in 3314 days)
	issuer= /C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA (hashed: b0f3e76e)
	issuer found in chain: NO - should be root certificate

How to get the real accessing IPs behind a load-balancing proxy

If you are using a load-balancing proxy such as squid, apache itself or pound, you will only find the proxy’s IP in your backend apache’s access/error logs. I tested two apache modules which replace the proxy’s IP by the X-Forwarded-For-IP provided by your load-balancing proxy: mod_rpaf and mod_extract_forwarded.

If you are running Debian, the easier installation will be mod_rpaf since it is provided in the (stable) sarge tree as well as in the (unstable) sid tree. The sid version will run smoothly under (testing) etch. As long as you are loggin IP addresses, the mod_rpaf is doing a great job. As soon as you are setting HostnameLookups On though, you will find your proxy’s hostname in the logs again – which is not what I wanted.

On OpenInfo you can download (local copy) the other solution I found, mod_extract_forwarded. Just download it to your apache server and extract the tar-archive. As found in the module’s documentation you should comment out the line

#define USING_proxy_http_module 1

by preceeding it with two slashes (//). This will be necessary if your apache server doesn’t load mod_proxy at this time (which backend servers usually don’t). Just don’t forget to remove the slashes again should you need and load mod_proxy some time later.

Compile the module by issuing

apxs2 -c -i -a mod_extract_forwarded.c

and you will find your module in your apache’s modules directory. The -a option will add a line to your apache configuration files which will then load the module automatically on every server (re-)start. The line will look like this – in case you have to remove it again:

LoadModule extract_forwarded_module /usr/lib/apache2/modules/

Within your site configuration (somewhere above the DocumentRoot line) you have to enable the module. Be sure to enter only the IP address of YOUR load-balancing proxy, no other proxies or even all proxies, otherwise you could find many fake IP addresses in your logs. Here are the configuration lines, be sure to change to YOUR load-balancing proxy’s IP address as it is seen by your apache-server (usually the IP you find for every access in your logs so far):

MEForder refuse,acceptMEFrefuse allMEFaccept

Restart your server and you should find the real IP addresses of your visitors in your logs.

Prevent apache from logging particular requests

If you don’t want apache to log every request in your access.log, maybe because you have thousands of requests from your monitoring system, you can prevent apache from logging these requests by two simple statements:

First you set an environment variable, second you don’t log when this variable is set:

SetEnvIf Remote_Host no_logCustomLog /var/log/apache2/access.log combined env=!no_log

There are more than just IP address matches, look into the apache documentation!