« February 2012 | Main | April 2012 »

5 posts from March 2012


Fixing an IIS7/isapi_redirect/Tomcat "Service Unavailable" Issue

I have not had much opportunity over the past several years to play with IIS7 on Windows 2008. Most of my installs have been Apache/Tomcat/JBoss on Linux but this past week I got my chance to finally work on IIS7 a little more in-depth with an isapi_redirect-under IIS7-to-Tomcat 6 setup. My experience reminded me why I do still prefer working on Linux (or any UNIX) over Windows.

Although there are a few additional steps, getting the isapi_redirect Tomcat Connector installed and working under IIS7 isn't all that much different from setting it up under previous IIS versions. I do have to update it to account for these IIS7-specific configuration steps but using my HOWTO as a starting point, I got to the point where I'm scratching my head because everything should be working. Instead of seeing my expected HTML output, though, I received a nice, short "The service is unavailable" message whenever I tried loading the app's homepage.

The isapi_redirect logs were strange; containing one entry I had not seen before followed by another which is like an old friend:

[Timestamp] [PID:TID] [error] ajp_validate::jk_ajp_common.c (2686): worker ajp can't resolve tomcat address localhost

[Timestamp] [PID:TID] [error] ajp_send_request::jk_ajp_common.c (1630): (ajp) connecting to backend failed. Tomcat is probably not started or is listening on the wrong port (errno=49)

"Worker ajp can't resolve tomcat address localhost"? Huh?

Well, tomcat was started and I could telnet to it's ajp connector port just fine so it certainly wasn't that! Tomcat is running on the same server IIS is running on so I couldn't blame the network or the firewall either.

Checking the hosts file under windows\system32\drivers\etc, I had two entries for localhost:    localhost
::1          localhost

Assuming the tomcat connector was picking up the IPV6 entry for localhost because it was the last occurrence of localhost in the file, I commented it out, restarted IIS, and, suddenly, IIS is talking to Tomcat. Telling a co-worker about my discovery, I decided to see what would happen if I removed the comment from in front of the entry and restarted IIS again. Fully expecting it to fail again, it, however, continued working fine. It was almost as if I imagined the whole problem and all I can think is, "Some people prefer this over Linux?".

UPDATE: (09/06/12) I managed to come across a case where this doesn't work and I'm starting to think that from now on if I'm working with Windows servers, just set the worker host in workers.properties to instead of localhost.


Validating SSL Certificates

Recently, @johngoggan notified me via tweet that (I am paraphrasing here) the insecure argument in cryptonark is still too secure in that cryptonark will still exit if the common name on the certificate does not match the host name that cryptonark is scanning. Although embarrassed that I missed this, I was also quite happy as this was the first bit of direct feedback on functionality that I have had with cryptonark since it was launched back in July, 2009.

insecure initially was set up to disable certificate verification and I was specifically thinking of those use cases where you are scanning a host using a self-signed certificate or when you have an invalid chain. My ultimate goal with it, however, was to emulate the insecure switch in cURL. As John pointed out, cryptonark version 0.4.6 and below will not perform the cipher scan if the hostname doesn't match the common name on the cert. I have addressed this by completely disabling host and certificate validation when insecure is used. While playing around with it though, I have come across some other functionality that I was not thrilled with, which required me slightly overhauling cryptonark's certificate verification functionality.

Typically, when you purchase a CA signed certificate, you specify a Common Name, like "www.somesite.com". Many CA's will automatically attach a Subject Alternative Name of "somesite.com" as part of your purchase, which allows browsers to connect using either the www.somesite.com name or the somesite.com name. In this example, www.somesite.com is the common name and somesite.com is a Subject Alternative Name. Although cryptonark still successfully validated the certificate if you specified the Subject Alternative Name as part of the host argument, if would only display the certificate Common Name in the output with no mention that a Subject Alternative Name of somesite.com exists for this cert. This might be confusing for some people scanning a host secured by an ssl crtificate that has a lot of Subject Alternative Names attached to it.

Below is a new script that you can use that will validate the certificate that secures a host or site and will display the Common Name and any Subject Alternative Names defined on the cert. Validation is performed against Mozilla's certificate store, included in the script using perl module Mozilla::CA. You will not need firefox installed on your machine but you will need to download Mozilla::CA from the CPAN. There is no insecure switch with this script as it's express purpose is to validate certificates but this script will be incorporated into CryptoNark 0.4.7. There are only two arguments, host and port. The script also makes use of my personal favorite module IO::Socket:SSL for connecting to ssl sites, Modern::Perl and Getopt::Long.

#!/usr/bin/env perl

use Modern::Perl;
use IO::Socket::SSL;
use Mozilla::CA;
use Getopt::Long;

my $host;
my $port;
my $verifymode = '0';

sub usage{
    say "Usage: chkcert.pl -h|--host <hostname> -p|--port <port number>";

usage() if ( ! GetOptions("h|host=s" => \$host, "p|port=s" => \$port) or ( ! defined $host) or ( ! defined $port) );

# Basic certificate checking
sub cert_info{
say "\nVerifying SSL Certificate...\n";
sleep 2;

my $certclient = IO::Socket::SSL->new(
  PeerHost => "$host:$port",
  SSL_ca_file => Mozilla::CA::SSL_ca_file(),
  SSL_verify_mode => $verifymode,
  SSL_version => 'TLSv1',
  SSL_cipher_list => 'RC4-SHA',
  Proto => 'tcp',
  Timeout => '5',
    || die("Certificate Peer Verification Failed\n\nCertificate not trusted. This could be due to:\n  + An invalid certificate chain\n  + A self-signed certificate\n  + You are scanning the IP address and not the DNS hostname\n  + Host $host does not appear to be listening on port $port\n  + You misspelled the intended host to be scanned.\n  + The CA signing this cert is not trusted by your version of Mozilla::CA\n\n");

  $certclient->verify_hostname($host, "http")
    || die("Hostname Verification Failed.\n$host does not match certificate's common name.\n\n");
  say "Certificate appears to be valid.";
  my $cn = $certclient->peer_certificate("cn");
  if ( $cn eq "" ) {
    say "Certificate Common Name: none";
    else {
      say "Certificate Commmon Name: " . $cn;

  my @san = $certclient->peer_certificate("subjectAltNames");
  my $san_names = join(" ", grep { !( $_ eq 2 ) } @san);

  if ( $san_names eq "" ) {
    say "Subject Alternative Names: none";
    else {
  say "Subject Alternative Names: " . $san_names;