SSL

Check for SSL certificate expiration of Radmind client certificates

You can find out if an SSL certificate has expired with the command below. I’ve found it useful to be able to check for expired certificates in my use of Radmind, where you can uniquely identify clients to the server with them.

$ openssl x509 -in /path/to/cert.pem -noout -checkend 0

I mention this command primarily because I reviewed the the OpenSSL x509 man page (“man x509”) that comes with Mac OS X Leopard, and it didn’t show the “checkend” option for the command. That was odd, because that option was just what I needed.

I did, however, find it documented in the usage statement-style help for the command:

$ openssl x509 --help

In that usage statement, the “checkend” option is described (with little punctuation) as a way to “check whether the cert expires in the next arg seconds [sic] exit 1 if so, 0 if not.” So, using zero seconds shows you if the certificate has already expired, while an integer greater than zero will show if it will expire in the future. No matter how many seconds you check against, you must examine the results from the exit code (the “$?” shell variable) to see if the certificate is or has expired.

I find this is tremendously useful knowledge when dealing with certificates in Radmind, where an expired certificate can mean the failure of a client to connect to the Radmind server. It could be beneficial in other circumstances, of course — but I don’t have those circumstances.

Taking this further, you could check for certificate expiration on a Radmind server — if your certificates are stored in the Radmind special directory for each hostname of a managed client. (Substitute one of your own managed clients’ hostnames for “hostname” in the path below.)

$ openssl x509 -in /var/radmind/special/hostname/private/var/radmind/cert/cert.pem -noout -checkend 0

Since you can do it for one client certificate, you could also loop through all of the certificates on a Radmind server. In this example, I’ll continue to use the path of /var/radmind even though, on Mac OS X, I’d generally prefer to specify the full /private/var/radmind; your Radmind server may not be on Mac OS X even if your clients are. Also, you may need to modify the “depth” parameter on your search to accommodate the paths on your server. Finally, I’ll change the “checkend” parameter to 604800, for seven days (60*60*24*7=604800). That produces something along the lines of:

for CERT_PATH in `find /var/radmind/special -name cert.pem -print -type f -depth 6`;
do
    CERT_HOST=`echo ${CERT_PATH} | cut -f 5 -d ’/’`
    openssl x509 -in ${CERT_PATH} -noout -checkend 604800
    RESULT=$?
    case ${RESULT} in
     0)
          echo "${CERT_HOST}: okay"
          ;;
     *)
          echo "${CERT_HOST}: expiring"
          ;;
esac
done

Change the last line to “done | grep expiring” if you only want to see the expiring certificates.

for CERT_PATH in `find /var/radmind/special -name cert.pem -print -type f -depth 6`;
do
    CERT_HOST=`echo ${CERT_PATH} | cut -f 5 -d ’/’`
    openssl x509 -in ${CERT_PATH} -noout -checkend 604800
    RESULT=$?
    case ${RESULT} in
     0)
          echo "${CERT_HOST}: okay"
          ;;
     *)
          echo "${CERT_HOST}: expiring"
          ;;
esac
done | grep expiring

It’s great to get just the CN of the certificate in these circumstances, since it’s likely you’ll want to act on just those that need attention. One way to do this relatively cleanly is to use OpenSSL x509’s “subject” and “nameopt” options, and then parse the output. Below, I’ll use awk for that. (Again, substitute one of your own managed clients’ hostnames for “hostname” in the path below.)

$ openssl x509 -in /private/var/radmind/special/hostname/private/var/radmind/cert/cert.pem -noout -subject -nameopt sep_multiline | awk '/CN/ {split($1,elements,"=") ; print elements[2] ;}'

To get the CNs of only those certificates needing attention:

for CERT_PATH in `find /var/radmind/special -name cert.pem -print -type f -depth 6`;
do
    openssl x509 -in ${CERT_PATH} -noout -checkend 604800
    RESULT=$?
    case ${RESULT} in
        0)
            ;;
        *)
            openssl x509 -in ${CERT_PATH} -noout -subject -nameopt sep_multiline | awk ‘/CN/ {split($1,elements,"=") ; print elements[2] ;}’
            ;;
    esac
done

Getting even fancier, you can find out just which certificate CNs are expiring or expired compared to the managed hosts listed in your config file. (Make sure you don’t get any that are commented out, and also watch out for curly braces.) You can accomplish much of that with this snippet:

for CERT_PATH in `find /var/radmind/special -name cert.pem -print -type f -depth 6`;
do
    openssl x509 -in ${CERT_PATH} -noout -checkend 604800
    EXPIRE_RESULT=$?
    case ${EXPIRE_RESULT} in
        0)
            ;;
        1)
            openssl x509 -in ${CERT_PATH} -noout -checkend 0
            EXPIRED_RESULT=$?
            case ${EXPIRED_RESULT} in
                1)
                    EXPIRE_DEGREE="expired"
                    ;;
                *)
                    EXPIRE_DEGREE="expiring"
                    ;;
            esac
            CERT_CN=`openssl x509 -in ${CERT_PATH} -noout -subject -nameopt sep_multiline | awk ‘/CN/ {split($1,elements,"=") ; print elements[2] ;}’`
            grep -E ’^{?[A-Za-z0-9.,]*’${CERT_CN}‘.’ —quiet /var/radmind/config
            GREP_RESULT=$?
            case ${GREP_RESULT} in
                0)
                    echo "${CERT_CN}: ${EXPIRE_DEGREE}, found uncommented in config file"
                    ;;
                *)
                    ;;
            esac
            ;;
    esac
done

Beyond checking for expiration on the server, it may be valuable to do so in your Radmind client scripts, especially if you favor SSL connections. If you find an expired certificate, you can take some remedial action right away that might allow the client to communicate with the server.

I thought about this a while, and the easiest way I came up with — after having already developed more complex logic — was to simply rename or remove the expired certificate from its normal path. Then, allow the client to connect with another authorization level where the client certificate is unnecessary. (Use of a client certificate implies Ramind’s “-w2” authorization level, while a lesser level would mean you’re performing hostname/DNS rather than certificate verification.) This would probably mean you have multiple Radmind server processes running, each on its own port, to accept such incoming requests on the server.

Syndicate content