Extension attribute to report on certificate expiration

Valued Contributor

Hey list, just wondering if anyone is using an extension attribute to report on a certificate's expiration date . . . .We use 802.1x to authorize all wired and wireless connections, so I'd like to be able to warn people before their certificates expire.
Nick Kalister
Desktop Engineering
Hitachi Data Systems
Office: 408.970.4316

750 Central Expressway
Building 32 : M/S 3240
Santa Clara, CA 95050


New Contributor III

Do you use computer or user certificates? If you using user certificates that its a bit tricky as you would need to read from the users keychain. Something like this would work

#!/usr/bin/perl -w
open(CERTS, "security export -k login.keychain -t certs|");
my $ifile = "";
my $thisfile = "";
$username = $ENV{USER};
print "Found user name: $username
$dsclmodulus = `/usr/bin/dscl localhost read /Search/Users/$username UserCertificate |
                        /usr/bin/sed -e 's/UserCertificate://' |
                        /usr/bin/xxd -r -p | openssl x509 -inform DER -outform PEM |
                        /usr/bin/openssl x509 -noout -modulus` ;
while(<CERTS>) {
   $ifile .= $_;
   $thisfile .= $_;
   if($_ =~ /^-+END(sw+)?sCERTIFICATE-+$/) {
      $subject = `echo "$thisfile" | /usr/bin/openssl x509 -noout -subject`;
      chomp($enddate = `echo "$thisfile" | /usr/bin/openssl x509 -noout -enddate`);
      $enddate =~ s/notAfter=//g;
        print "Checking Certificate: $subject";
        if($subject =~ m/$username/){
                $crtmodulus = `echo "$thisfile" | /usr/bin/openssl x509 -noout -modulus`;
                print "Checking Certificate: $crtmodulus";

                if($crtmodulus = $dsclmodulus){
                        print "Found Certificate Match
: $subject";
                        print "<result>$enddate</result>
                        exit 1;
      $thisfile = "";
exit 0


But has a ton of caveats , i.e would need the USER variable set, so it would run in the context of the user ( for access to the keychain) , i.e. basically in the Casper lexicon it would have to run as something like a LaunchAgent or loginhook ( with some tweaks) , and have it drop its output somewhere that would be picked up by extension attribute.

If your using computer cert this is a whole lot easier as you can just run it natively as an extension attribute as would just be reading from the system keychain.

To break the script down , its reading the (10.7 style attribute names FYI as I was testing on my own box) certificate attribute which is put there when your using a Microsoft CA ISS HTTP enrollment style system. This modulus should match whatever they are using in their keychain to auth. Once you find the certificate its trivial to grab its date.

Converting to a System cert would be pretty easy , effectively changing the command to something like

open(CERTS, "security export -k /Library/Keychains/System.keychain -t certs|");

and changing the dscl code to search for the computers cert, though I don't have something like that setup at the moment as I normally am only involved in projects that are using user certificates.

Example output


Found user name: acid
Checking Certificate: subject= /CN=Apple Configurator (00:00:00:00:00:D8)/O=sand.wallcity.org/C=US
Checking Certificate: subject= /DC=example/DC=org/DC=wallcity/CN=Users/CN=Zack Smith/emailAddress=acidprimePLEASEDONT@SPAMMEwallcity.org
Checking Certificate: Modulus=E36F027DCFB6D56FD0D990AAD6A628FEF72B608E99BBD58952566F601E2AD717D48B05E0000000BF95FDC5CD6768243228CF5EC2B85947F510D791CAE4353ED0610C9139CEBD67052B1A255152111111176885CD8299D4B874D06F71A0128982C37D4400FCE9F8EC13E4F131B84AE0C66567A5AE7FCDF27493DFC79679CCACC864749ECDC4F105ED6F722CD1D6DC85B7CE80477ECE181612E74BC220C4B941C9A95C870F98129B9E6080AB2C08D460652329A249DE04256C6E8873A227556B3563662EFA87E5EFE65B4F9D03203B38C3756BE368B024F6200B309C03756F06A495472536DB343D0C45F41D08B164107066474E653CFC0A122906B4B0B35C19F
Found Certificate Match
: subject= /DC=example/DC=org/DC=wallcity/CN=Users/CN=Zack Smith/emailAddress=acidprimePLEASEDONT@SPAMMEwallcity.org
<result>Oct  3 21:53:59 2012 GMT</result>

Honored Contributor

You can easily find the owner of console and set it to a variable with

user=`ls -la /dev/console | cut -d " " -f 4`

which will tell you the currently logged in user and set it to $user. You can then do

sudo -u $user <command as user>

or simply use the security command and specify the keychain you want look at with the -k flag and specify the path to the keychain with


Let me know if you need help with that.

New Contributor II

@acidprime I've been trying to do something similar, to report if there is an expired AD user cert in the login.keychain, or if there is no AD user cert in the login.keychain (vpn issues are generally caused by one or the other condition). The issue I continually run up against (confirmed by others in many other posts) is that when the login.keychain has multiple user certificates with the same name, only one expiration date will be returned. I haven't been able to find a way to loop through login.keychain certificates with the same name and report on each expiration date. I've tried an array, but no luck; I can only report on login.keychain certificate expiration dates as long as no more than one certificate exists with the same name.

Contributor III

When running

/usr/bin/security find-certificate -a -p -Z /Library/Keychains/apsd.keychain | /usr/bin/openssl x509 -noout -enddate| cut -f2 -d=

I end up with Mar 13 03:57:11 2021 GMT which does not play nice as a Date EA. How would we change this to the more EA friendly yyyy-mm-dd format?


@swhps You can add | date +"%Y-%m-%d %T" to the end and that should format it correctly.

So the entire string would be...

/usr/bin/security find-certificate -a -p -Z /Library/Keychains/apsd.keychain | /usr/bin/openssl x509 -noout -enddate | cut -f2 -d= | date +"%Y-%m-%d %T"