package es.uji.security.keystore.pkcs11; import java.io.ByteArrayInputStream; import java.io.File; import java.lang.reflect.Method; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Vector; import sun.security.pkcs11.wrapper.CK_ATTRIBUTE; import sun.security.pkcs11.wrapper.CK_C_INITIALIZE_ARGS; import sun.security.pkcs11.wrapper.CK_TOKEN_INFO; import sun.security.pkcs11.wrapper.PKCS11; import sun.security.pkcs11.wrapper.PKCS11Constants; import sun.security.pkcs11.wrapper.PKCS11Exception; public class PKCS11Helper { private static int MAX_CERTS = 1000; private static long CKM_RSA_PKCS= 0x00000001; private static long CKM_SHA1_RSA_PKCS= 0x00000006; String _initArgs, _pk11LibPath, _name; Vector<X509Certificate> certificates = new Vector<X509Certificate>(); public PKCS11Helper(String pk11LibPath, String initArgs) throws PKCS11HelperException { _initArgs = initArgs; _pk11LibPath = pk11LibPath; initialize(); } public PKCS11Helper(String pk11LibPath) throws PKCS11HelperException { _initArgs = null; _pk11LibPath = pk11LibPath; initialize(); } public String getName() { return _name; } private void initialize() throws PKCS11HelperException { long hSession = 0; long[] slots; boolean found = false; CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[1]; CK_ATTRIBUTE attr = new CK_ATTRIBUTE(); CK_TOKEN_INFO ckti = null; PKCS11 p11 = getP11Instance(); try { slots = p11.C_GetSlotList(true); //true is token present, false to get all slots. } catch (Exception e) { throw new PKCS11HelperException("Getting Slot List::" + e.getMessage(), PKCS11HelperException.errorType.ERR_GET_SLOT_LIST); } for (long k : slots) { try { System.out.println("Slot k = " + k ); for (long x: p11.C_GetMechanismList(k)){ if ( x == CKM_RSA_PKCS || x == CKM_SHA1_RSA_PKCS ){ System.out.println("Slot " + k + " has signature capabilities"); break; } } ckti = p11.C_GetTokenInfo(k); _name = new String(ckti.label); } catch (Exception e) { throw new PKCS11HelperException("Getting token Info::" + e.getMessage(), PKCS11HelperException.errorType.ERR_GET_TOKEN_INFO); } try { hSession = p11.C_OpenSession(k, PKCS11Constants.CKF_SERIAL_SESSION, null, null); } catch (Exception e) { throw new PKCS11HelperException("Opening a new Session::" + e.getMessage(), PKCS11HelperException.errorType.ERR_OPEN_SESSION); } attr.type = PKCS11Constants.CKA_CLASS; attr.pValue = PKCS11Constants.CKO_CERTIFICATE; attrs[0] = attr; try { p11.C_FindObjectsInit(hSession, attrs); long[] l = p11.C_FindObjects(hSession, MAX_CERTS); p11.C_FindObjectsFinal(hSession); for (long i : l) { CK_ATTRIBUTE attrPriv = new CK_ATTRIBUTE(); CK_ATTRIBUTE[] attrsP = new CK_ATTRIBUTE[2]; attrPriv.type = PKCS11Constants.CKA_CLASS; attrPriv.pValue = PKCS11Constants.CKA_PRIVATE;//CKO_PRIVATE_KEY; attr.type = PKCS11Constants.CKA_ID; attr.pValue = getID(hSession, i, p11); if (attr.pValue != null) { attrsP[0] = attrPriv; attrsP[1] = attr; p11.C_FindObjectsInit(hSession, attrsP); long[] m = p11.C_FindObjects(hSession, MAX_CERTS); if (m.length > 0) { found = true; certificates.add(loadCert(hSession, i, p11)); } p11.C_FindObjectsFinal(hSession); } } } catch (Exception e) { e.printStackTrace(); throw new PKCS11HelperException("Unsuccesfully FindObjects secuence::" + e.getMessage(), PKCS11HelperException.errorType.ERR_FIND_OBJECTS); } try { p11.C_CloseSession(hSession); if (found) break; } catch (Throwable e) { throw new PKCS11HelperException("Cannot close sesion::" + e.getMessage(), PKCS11HelperException.errorType.ERR_CLOSE_SESSION); } } try { // Should be revised against the code of jdk. // That should be done under normal conditions, but when using com.sun.security classes, // something happen that make future SunPKCS11 provider against mozilla library // fails on session handle. // p11.C_Finalize(hSession); p11 = null; Runtime.getRuntime().gc(); } catch (Throwable e) { throw new PKCS11HelperException("Cannot Finalize::" + e.getMessage(), PKCS11HelperException.errorType.ERR_FINALIZE); } } private X509Certificate loadCert(long session, long oHandle, PKCS11 p11) throws PKCS11Exception, CertificateException { CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(PKCS11Constants.CKA_VALUE) }; p11.C_GetAttributeValue(session, oHandle, attrs); byte[] bytes = attrs[0].getByteArray(); if (bytes == null) { throw new CertificateException("unexpectedly retrieved null byte array"); } CertificateFactory cf = CertificateFactory.getInstance("X.509"); return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(bytes)); } private byte[] getID(long session, long oHandle, PKCS11 p11) throws PKCS11Exception, CertificateException { byte[] bytes = null; CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(PKCS11Constants.CKA_ID) }; p11.C_GetAttributeValue(session, oHandle, attrs); if (attrs[0].pValue != null) { bytes = attrs[0].getByteArray(); } return bytes; } public X509Certificate[] getCertificates() throws PKCS11HelperException { X509Certificate[] xcer = new X509Certificate[0]; return certificates.toArray(xcer); } public long[] getSignatureCapableSlots() throws PKCS11HelperException{ long[] slots; Vector<Long> vslots = new Vector<Long>(); PKCS11 p11 = getP11Instance(); try { slots = p11.C_GetSlotList(true); //true is token present, false to get all slots. } catch (Exception e) { throw new PKCS11HelperException("Getting Slot List::" + e.getMessage(), PKCS11HelperException.errorType.ERR_GET_SLOT_LIST); } for (long k : slots) { try { for (long x: p11.C_GetMechanismList(k)){ if ( x == CKM_SHA1_RSA_PKCS ){ vslots.add(k); break; } } } catch (PKCS11Exception e) { throw new PKCS11HelperException("Cannot get Mechanism list::" + e.getMessage(), PKCS11HelperException.errorType.ERR_GET_SLOT_LIST); } } long[] res= new long[vslots.size()]; for (int i=0; i<vslots.size(); i++){ res[i]= vslots.get(i); } return res; } public PKCS11 getP11Instance() throws PKCS11HelperException{ Method[] methods = PKCS11.class.getMethods(); Method p11Getinstance = null; PKCS11 p11= null; CK_C_INITIALIZE_ARGS cia = new CK_C_INITIALIZE_ARGS(); cia.pReserved = (Object) _initArgs; cia.flags = 0; for (int i = 0; i < methods.length; i++) { if (methods[i].getName().equals("getInstance")) p11Getinstance = methods[i]; } try { File _fpk11LibPath = new File(_pk11LibPath); _pk11LibPath = _fpk11LibPath.getCanonicalPath(); String version = System.getProperty("java.version"); if (version.indexOf("1.5") > -1) { // JRE 1.5 p11 = (PKCS11) p11Getinstance.invoke(null, new Object[] { _pk11LibPath, cia, false }); } else { p11 = (PKCS11) p11Getinstance.invoke(null, new Object[] { _pk11LibPath, "C_GetFunctionList", cia, false }); } } catch (Exception e) { e.printStackTrace(); throw new PKCS11HelperException("Problem using java reflection with pkcs11 classes::" + e.getMessage(), PKCS11HelperException.errorType.ERR_INVOKE_INITIALIZE); } return p11; } public static void main(String[] args) throws PKCS11HelperException{ PKCS11Helper pk11h= new PKCS11Helper("/usr/lib/libclauerpkcs11.so", ""); for (X509Certificate xc: pk11h.getCertificates()){ System.out.println(xc.getSubjectDN()); } //Lets try to get slots by a given mechanism: for (long i: pk11h.getSignatureCapableSlots()){ System.out.println("Slot " + i + " is signature capable."); } } }