tags:

views:

543

answers:

2

I need to determine the expiration date of the SSL certificates on my IIS boxes programatically. Ideally I would want to do this in C#, but if VB script is the only way that is acceptable as well.

Environment => IIS versions 6 & 7, .NET 2.0, Windows 2003 & 2008

Thanks

+5  A: 

I am not familiar with a way to do this check with VBS and/or WMI as that is possibly a security whole because it could potentially expose the private key. However, there is a way to leverage a normal HTTPS connection to get to the public information about the certificate. If you connect to any secure web site using IE, you can then go to the File menu and look at the Properties and then click the Certificates button. That shows the public certificate information dialog for the site. You can get to this information programmatically using C#.

Basically, what you have to do is to open a TCP connection to the server on port 443 and then receive the SSL data. In this data stream is the public information about the certificate and you can validate it and extract all the information you need from it, including expiration date. Here is some sample code:

static void Main(string[] args) {
    foreach (string servername in args) {
        Console.WriteLine("\n\nFetching SSL cert for {0}\n", servername);
        TcpClient client = new TcpClient(servername, 443);
        SslStream sslStream = new SslStream(client.GetStream(), false, callback, null);

        try {
            sslStream.AuthenticateAsClient(servername);
        } catch (AuthenticationException ex) {
            Console.WriteLine("Exception: {0}", ex.Message);
            if (ex.InnerException != null) {
                Console.WriteLine("Inner exception: {0}", ex.InnerException.Message);
            }
            Console.WriteLine("Authentication failed - closing the connection.");
        }

        client.Close();
    }
}

And the code for the callback that handles certificate information:

static RemoteCertificateValidationCallback callback = delegate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors sslError) {
    X509Certificate2 x509 = new X509Certificate2(cert);

    // Print to console information contained in the certificate.
    Console.WriteLine("Subject: {0}", x509.Subject);
    Console.WriteLine("Issuer: {0}", x509.Issuer);
    Console.WriteLine("Version: {0}", x509.Version);
    Console.WriteLine("Valid Date: {0}", x509.NotBefore);
    Console.WriteLine("Expiry Date: {0}", x509.NotAfter);
    Console.WriteLine("Thumbprint: {0}", x509.Thumbprint);
    Console.WriteLine("Serial Number: {0}", x509.SerialNumber);
    Console.WriteLine("Friendly Name: {0}", x509.PublicKey.Oid.FriendlyName);
    Console.WriteLine("Public Key Format: {0}", x509.PublicKey.EncodedKeyValue.Format(true));
    Console.WriteLine("Raw Data Length: {0}", x509.RawData.Length);

    if (sslError != SslPolicyErrors.None) {
        Console.WriteLine("Certificate error: " + sslError);
    }

    return false;
};

And the cool thing is that this approach should, technically, work with any webserver... I only tested on IIS 6 and 7.

Jonas Gorauskas
A: 

You should be able to do this with Microsoft.Web.Administration also, see this post and this blog post. I think you should be able to reverse it - get the correct store, then the correct certificate.

[edit]Hm, I got puzzled now. I'm not sure Microsoft.Web.Administration is supported for anything below IIS 7..[/edit]

Onkelborg