lou_cypher
lou_cypher

Reputation: 311

Checking certificates expiration dates in java keystore

My java application uses a keystore file in which I have a certificate which is used in ssl connection with active directory server. What I have to do is to check its expiration date and prompt user if its close to expire. I have to do it while my application starts. My idea is to use external program: keytool to display info about certain certificate in the keystore and then do some parsing operations on a string which keytool outputs to find this validation date.

Here's the output of a specific keytool command:

Owner:
Issuer: CN=CPD Root CA, DC=cpd, DC=local<br>
Serial number: 39e8d1610002000000cb
<br>Valid from: Wed Feb 22 21:36:31 CET 2012 until: Thu Feb 21 21:36:31 CET 2013
Certificate fingerprints: <br>
         MD5:  82:46:8B:DB:BC:5C:64:21:84:BB:68:E3:4B:D4:35:70<br>
         SHA1: 35:52:CA:F2:11:66:1E:50:63:BC:53:A5:50:C1:F0:1E:62:81:BC:3F<br>
         Signature algorithm name: SHA1withRSA

Problem would be with parsing date since I can't be sure in which format it is displayed.

Is there any easier way to check expiration date of certificates included in java keystore file?

Upvotes: 26

Views: 49965

Answers (4)

Rahamath
Rahamath

Reputation: 541

String secret = "secret123";
InputStream ins = new FileInputStream("/test.jks");
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(ins, secret.toCharArray());
Enumeration<String> aliases = keyStore.aliases();
while(aliases.hasMoreElements()) {
    String alias = aliases.nextElement();
    System.out.println("alias : " + alias);
    if(keyStore.getCertificate(alias).getType().equals("X.509")) {
        X509Certificate cert = (X509Certificate) keyStore.getCertificate(alias);
        System.out.println(alias + " from " + cert.getNotBefore());
        System.out.println(alias + " to " + cert.getNotAfter());
        try {
            cert.checkValidity();
        } catch (CertificateExpiredException e) {
            // if the certificate has expired.
            e.printStackTrace();
        } catch (CertificateNotYetValidException e) {
            // if the certificate is not yet valid. it means the certificate validitity start date is future date.
            e.printStackTrace();
        }               
    }
}

Upvotes: 0

user207421
user207421

Reputation: 311052

Use the java.security.Keystore class to load the keystore and enumerate its contents, and check each certificate for expiry.

Upvotes: 9

Madcat
Madcat

Reputation: 11

Here's a Powershell script I wrote to check a JKS, extract the alias and expiry date, and email me a table listing of certs expiring in the next 60 days (adjustable to whatever you want). I have scheduled this to run this in Task Scheduler on the 1st of every month

It's in 2 phases:

  1. use a CMD script to output the contents of the JKS to a text file
  2. Powershell then interrogates that data

The reason the CMD is there is that when you use the command via CMD, it extracts the required data and uses both LF and CRLF to separate the cert's data - this then makes it easy to join the lines together for the Powershell. Running the command via the Powershell script just creates CRLF line breaks

PS: I am a beginner Powershell coder so please be gentle :) but those with more experience please feel free to optimise this code

This is for Australian time, catering for standard (AEST) and daylight savings times (AEDT)

CMD:

D:\path_to_java\jvm\jvm\bin\keytool.exe -list -v -keystore D:\path_to_JKS\CertStore.jks -storepass "my_jks_pass" | findstr "Alias until" > D:\Tools\Scripts\CertExpiryCheck\certlist_temp.txt

POWERSHELL:

# MUST use CMD to run below command line so that it creates both LF and CRLF breaks (Powershell just creates CRLF)
Start-Process -NoNewWindow -Wait -FilePath "C:\Windows\System32\cmd.exe" -ArgumentList {/c "D:\Tools\Scripts\CertExpiryCheck\Extract_cert_info.cmd"}
 
$original_file ='D:\Tools\Scripts\CertExpiryCheck\certlist_temp.txt'
$new_file1 ='D:\Tools\Scripts\CertExpiryCheck\new_certs1.txt'
$new_file2 ='D:\Tools\Scripts\CertExpiryCheck\certlist.txt'
$to = "[email protected]"
$add_days = 60

$fileexists = Test-Path -Path $original_file
$checkiffileisempty = (Get-ChildItem -Path $original_file).Length -eq "0"
If (($fileexists -eq $False) -or ($checkiffileisempty -eq $True)) 
{
    Write-Host "$original_file does not exist or is empty !"
    break 
}


#replace CRLF with space
$text1 = [IO.File]::ReadAllText($original_file) -replace "`r`n", " "
[IO.File]::WriteAllText($new_file1, $text1)
#replace LF with CRLF
$text2 = [IO.File]::ReadAllText($new_file1) -replace "`n", "`r`n"
[IO.File]::WriteAllText($new_file2, $text2)

$InXDays = [DateTime]::Now.AddDays($add_days)

# Create a DataTable
$table = New-Object system.Data.DataTable "ExpiringCertsTable"
$col1 = New-Object system.Data.DataColumn CertAlias,([string])
$col2 = New-Object system.Data.DataColumn ExpiringOn,([string])
$table.columns.add($col1)
$table.columns.add($col2)


$File = Get-Content $new_file2
foreach($line in $File)
{
    $alias1, $until1 = $line -Split "Valid from:" 
    $aliastext, $certname = $alias1 -Split ":"
    $from1, $untildate = $until1 -Split "until: " 

    if($untildate.Contains("AEDT"))
    {
        $cert_exp_date = [datetime]::ParseExact($untildate, 'ddd MMM dd HH:mm:ss AEDT yyyy', [cultureinfo]'en-AU')
    }

    if($untildate.Contains("AEST"))
    {
        $cert_exp_date = [datetime]::ParseExact($untildate, 'ddd MMM dd HH:mm:ss AEST yyyy', [cultureinfo]'en-AU')
    }

    if($cert_exp_date -le $InXDays )
    {
        Write-Output ">>> $certname <<<`thas expired or will be expiring on `t*** $untildate ***"

        $row = $table.NewRow()
        $row.CertAlias = $certname
        $row.ExpiringOn = $untildate
        $table.Rows.Add($row)
    }
}


# Create column headers of Table
$HtmlTable1 = "<table border='1' align='Left' cellpadding='2' cellspacing='0' style='color:black;font-family:arial,helvetica,sans-serif;text-align:left;'>
<tr style ='font-size:13px;font-weight: normal;background-color: LightBlue'>
<th align=left><b>Certificate Alias</b></th>
<th align=left><b>Expiring On</b></th>
</tr>"

# Insert data into Table
foreach ($row in $table.Rows)
{ 
    $HtmlTable1 += "<tr style='font-size:13px;background-color:#FFFFFF'>
    <td>" + $row[0] + "</td>
    <td>" + $row[1] + "</td>
    </tr>"
}

$HtmlTable1 += "</table>"

#email report
$smtpserver = "smtp.server.com"
$from = "$env:[email protected]"
$subject = "Certs expiring in next $add_days days on $env:COMPUTERNAME"
$body = "List of certs in D:\path_to_JKS\CertStore.jks expiring in the next $add_days days:<br /><br />" + $HtmlTable1
Send-MailMessage -smtpserver $smtpserver -from $from -to $to -subject $subject -body $body -bodyashtml

#clean up temp files
Remove-Item $original_file 
Remove-Item $new_file1 
Remove-Item $new_file2

Upvotes: 1

William
William

Reputation: 341

Thanks for the direction EJP, here is a block of what I came up with.

    try {
        KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
        keystore.load(new FileInputStream("keystoreLocation"), "keystorePassword".toCharArray());
        Enumeration<String> aliases = keystore.aliases();
        while(aliases.hasMoreElements()){
            String alias = aliases.nextElement();
            if(keystore.getCertificate(alias).getType().equals("X.509")){
                System.out.println(alias + " expires " + ((X509Certificate) keystore.getCertificate(alias)).getNotAfter());
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

Upvotes: 29

Related Questions