I\'m bascially looking for someplace to start learning how to interface with a government CAC card using java.
Ultimately, my goal is to find out how to use
Look into using cert authentication using an SSO type application such as OpenSSO or JOSSO. The agent should be simpler to embed, and they have already implemented most of the details. If you need to do it yourself, they also have a lot of documentation related to the steps needed such as: digital certificates setup
Are you creating the web application, or trying to write software that runs at the client (sort of like your own web browser)?
If you are creating a web application, it's pretty much just standard client certification authentication. The fact that the certificate came from a hardware token doesn't change much for the server; if you want to accept only CAC certificates, you can specify set of acceptable certificate policies when the server validates the client certificate. (Policy validation is a standard part of PKIX validation.) If this application is for a government customer, you'll need to work closely with their security team to ensure that your solution meets their requirements, which can be stringent. If this is your scenario, let me know and I'll update my answer with some of the issues that we encountered.
If you are writing a client, and need to access the physical reader, you may be able to use the Sun PKCS #11 provider, since Java 1.5. I've experimented with this provider, and you can read more about it in another answer.
On the server, you should check that the certificate is not revoked. However, some of these CRLs are enormous—we had over 100 Mb worth of CRL files, and the built-in Sun revocation checker does not scale well to this size.
You will also need to make sure that you have the right root CA certificates in Tomcat's "trust" key store (the government root CA certs are little harder to find because they want to make sure users are verifying them properly). We also found that Firefox does not send the entire certificate chain unless users import the intermediate certificates into their browser manually.
You need to create a file called card.config
and include the following lines in it:
name = myConfig
library = /path/to/library/that/implements/cac/card/reader
And then try this:
import java.io.*;
import java.util.*;
import java.security.cert.CertificateException;
import java.security.KeyStoreException;
import java.security.cert.X509Certificate;
import java.security.KeyStore;
import java.security.Provider;
import java.security.SecureRandom;
import java.security.Security;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
public class Test
{
public static void main(String arg[]) throws Exception
{
try
{
//Create our certificates from our CAC Card
String configName = "card.config";
Provider p = new sun.security.pkcs11.SunPKCS11(configName);
Security.addProvider(p);
//Get the pin from user entered data
Console c = System.console();
char[] pin = c.readPassword("Enter your PIN: ");
KeyStore cac = null;
cac = KeyStore.getInstance("PKCS11");
cac.load(null, pin);
showInfoAboutCAC(cac);
}
catch(Exception ex)
{
//System.out.println("*" + ex.getMessage());
ex.printStackTrace();
System.exit(0);
}
}
public static void showInfoAboutCAC(KeyStore ks) throws KeyStoreException, CertificateException
{
Enumeration<String> aliases = ks.aliases();
while (aliases.hasMoreElements())
{
String alias = aliases.nextElement();
X509Certificate[] cchain = (X509Certificate[]) ks.getCertificateChain(alias);
System.out.println("Certificate Chain for : " + alias);
for (int i = 0; i < cchain.length; i ++)
{
System.out.println(i + " SubjectDN: " + cchain[i].getSubjectDN());
System.out.println(i + " IssuerDN: " + cchain[i].getIssuerDN());
}
}
}
}
At this point you have a keystore that you can use to create the ssl socket to talk to the https web server.