Reputation: 311
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
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
Reputation: 311052
Use the java.security.Keystore
class to load the keystore and enumerate its contents, and check each certificate for expiry.
Upvotes: 9
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:
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
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