Red Hat Application Migration Toolkit
package ee.sk.digidoc.factory; import ee.sk.digidoc.Base64Util; import ee.sk.digidoc.DigiDocException; import ee.sk.digidoc.Signature; import ee.sk.digidoc.SignedDoc; import ee.sk.digidoc.TokenKeyInfo; import ee.sk.digidoc.factory.SignatureFactory; import ee.sk.utils.ConfigManager; import ee.sk.utils.ConvertUtils; import iaik.pkcs.pkcs11.InitializeArgs; import iaik.pkcs.pkcs11.Mechanism; import iaik.pkcs.pkcs11.Module; import iaik.pkcs.pkcs11.Notify; import iaik.pkcs.pkcs11.Session; import iaik.pkcs.pkcs11.Slot; import iaik.pkcs.pkcs11.SlotInfo; import iaik.pkcs.pkcs11.Token; import iaik.pkcs.pkcs11.TokenException; import iaik.pkcs.pkcs11.objects.RSAPrivateKey; import iaik.pkcs.pkcs11.objects.X509PublicKeyCertificate; import iaik.pkcs.pkcs11.wrapper.PKCS11Exception; import java.io.ByteArrayInputStream; import java.io.IOException; import java.security.AccessController; import java.security.PrivilegedExceptionAction; import java.security.Provider; import java.security.Security; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Vector; import org.apache.log4j.Logger; public class PKCS11SignatureFactory implements SignatureFactory { private Module m_pkcs11Module = null; private TokenKeyInfo[] m_tokens = null; private Session m_currentSession = null; private TokenKeyInfo m_selToken = null; private Provider m_secProvider = null; private static Logger m_logger = Logger.getLogger(PKCS11SignatureFactory.class); private static boolean m_isInitialized; byte[] tsign = new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; public PKCS11SignatureFactory() { m_isInitialized = false; } public void init() throws DigiDocException { if(this.m_pkcs11Module == null) { this.initPKCS11(); } if(this.m_secProvider == null) { this.initProvider(); } } public void initPKCS11() throws DigiDocException { try { if(m_logger.isInfoEnabled()) { m_logger.info("Loading PKCS11 driver: " + ConfigManager.instance().getProperty("DIGIDOC_SIGN_PKCS11_DRIVER") + " libpath: " + System.getProperty("java.library.path")); } this.m_pkcs11Module = (Module)AccessController.doPrivileged(new PrivilegedExceptionAction() { public Object run() throws IOException { String moduleName = ConfigManager.instance().getProperty("DIGIDOC_SIGN_PKCS11_DRIVER"); Module m = Module.getInstance(moduleName); return m; } }); try { if(!m_isInitialized) { this.m_pkcs11Module.initialize((InitializeArgs)null); m_isInitialized = true; } } catch (PKCS11Exception var2) { m_logger.error("Pkcs11 error: " + var2); if(var2.getErrorCode() == 401L) { m_logger.error("PKCS11 already loaded ok"); m_isInitialized = true; } else { DigiDocException.handleException(var2, 57); } } this.m_tokens = this.getTokenKeys(); } catch (Exception var3) { this.m_pkcs11Module = null; DigiDocException.handleException(var3, 57); } if(this.m_tokens == null || this.m_tokens.length == 0) { throw new DigiDocException(85, "Error reading signature certificates from card!", (Throwable)null); } } public TokenKeyInfo[] getTokenKeys() throws DigiDocException { Vector vec = new Vector(); Session sess = null; try { CertificateFactory arr = CertificateFactory.getInstance("X.509"); Slot[] i = this.m_pkcs11Module.getSlotList(true); int nNr = 0; for(int i1 = 0; i != null && i1 < i.length; ++i1) { SlotInfo si = i[i1].getSlotInfo(); if(m_logger.isDebugEnabled()) { m_logger.debug("Slot " + i1 + ": " + si); } if(si.isTokenPresent()) { Token tok = i[i1].getToken(); if(m_logger.isDebugEnabled()) { m_logger.debug("Token: " + tok); } sess = tok.openSession(true, false, (Object)null, (Notify)null); X509PublicKeyCertificate templCert = new X509PublicKeyCertificate(); sess.findObjectsInit(templCert); iaik.pkcs.pkcs11.objects.Object[] certs = null; do { certs = sess.findObjects(1); if(certs != null && certs.length > 0) { if(m_logger.isDebugEnabled()) { m_logger.debug("Certs: " + certs.length); } for(int j = 0; certs != null && j < certs.length; ++j) { X509PublicKeyCertificate x509 = (X509PublicKeyCertificate)certs[j]; byte[] derCert = x509.getValue().getByteArrayValue(); X509Certificate cert = (X509Certificate)arr.generateCertificate(new ByteArrayInputStream(derCert)); TokenKeyInfo tki = new TokenKeyInfo(nNr, i[i1].getSlotID(), tok, x509.getId().getByteArrayValue(), x509.getLabel().toString(), cert); ++nNr; if(m_logger.isDebugEnabled()) { m_logger.debug("Slot: " + i1 + " cert: " + j + " nr: " + tki.getCertSerial() + " CN: " + tki.getCertName() + " id: " + tki.getIdHex() + " signature: " + tki.isSignatureKey()); } vec.add(tki); } } } while(certs != null && certs.length > 0); sess.closeSession(); sess = null; } } } catch (Exception var24) { this.m_pkcs11Module = null; DigiDocException.handleException(var24, 57); } finally { try { if(sess != null) { sess.closeSession(); } } catch (Exception var23) { m_logger.error("Error closing session: " + var23); } } TokenKeyInfo[] var26 = new TokenKeyInfo[vec.size()]; for(int var27 = 0; var27 < vec.size(); ++var27) { var26[var27] = (TokenKeyInfo)vec.elementAt(var27); } return var26; } private void initProvider() throws DigiDocException { try { this.m_secProvider = (Provider)Class.forName(ConfigManager.instance().getProperty("DIGIDOC_SECURITY_PROVIDER")).newInstance(); Security.addProvider(this.m_secProvider); } catch (Exception var2) { this.m_secProvider = null; DigiDocException.handleException(var2, 58); } } public TokenKeyInfo[] getTokensOfType(boolean bSign) { int nToks = 0; boolean bKeyUsageCheck = ConfigManager.instance().getBooleanProperty("KEY_USAGE_CHECK", true); for(int arr = 0; this.m_tokens != null && arr < this.m_tokens.length; ++arr) { TokenKeyInfo i = this.m_tokens[arr]; if(m_logger.isDebugEnabled()) { m_logger.debug("Token: " + arr + " is-sign: " + i.isSignatureKey() + " is-crypt: " + i.isEncryptKey() + " nr: " + i.getCertSerial() + " CN: " + i.getCertName() + " id: " + i.getIdHex()); } if(bSign && (i.isSignatureKey() || !bKeyUsageCheck) || !bSign && i.isEncryptKey()) { ++nToks; } } TokenKeyInfo[] var8 = new TokenKeyInfo[nToks]; int var9 = 0; for(int j = 0; this.m_tokens != null && var9 < this.m_tokens.length; ++var9) { TokenKeyInfo tki = this.m_tokens[var9]; if(bSign && (tki.isSignatureKey() || !bKeyUsageCheck) || !bSign && tki.isEncryptKey()) { if(m_logger.isDebugEnabled()) { m_logger.debug("Using token: " + var9 + " is-sign: " + tki.isSignatureKey() + " is-crypt: " + tki.isEncryptKey() + " nr: " + tki.getCertSerial() + " CN: " + tki.getCertName() + " id: " + tki.getIdHex()); } var8[j++] = tki; } } return var8; } public TokenKeyInfo getTokenWithSlotIdAndLabel(long nSlotId, String label) { for(int i = 0; this.m_tokens != null && i < this.m_tokens.length; ++i) { TokenKeyInfo tki = this.m_tokens[i]; if(tki.getSlot() == nSlotId && tki.getLabel().equals(label)) { return tki; } } return null; } public X509Certificate getCertificateWithSlotIdAndLabel(long nSlotId, String label) { TokenKeyInfo tki = this.getTokenWithSlotIdAndLabel(nSlotId, label); return tki != null?tki.getCert():null; } public String[] getAvailableTokenNames() throws DigiDocException { if(this.m_pkcs11Module == null) { this.initPKCS11(); } String[] names = new String[this.m_tokens.length]; for(int i = 0; this.m_tokens != null && i < this.m_tokens.length; ++i) { TokenKeyInfo tki = this.m_tokens[i]; names[i] = tki.getCertName(); } return names; } public void openSession(TokenKeyInfo tki, String pin) throws DigiDocException { if(this.m_pkcs11Module == null) { this.initPKCS11(); } try { if(this.m_currentSession != null) { this.closeSession(); } if(m_logger.isDebugEnabled()) { m_logger.debug("Open session for token: " + tki); } if(m_logger.isDebugEnabled()) { m_logger.debug("Open session for: " + (tki != null?tki.getCertName() + " id: " + tki.getIdHex() + " sign: " + tki.isSignatureKey() + " crypt: " + tki.isEncryptKey():"NULL")); } if(tki != null) { this.m_currentSession = tki.getToken().openSession(true, false, (Object)null, (Notify)null); this.m_selToken = tki; } else if(m_logger.isDebugEnabled()) { m_logger.debug("No suitable token found!"); } if(this.m_currentSession != null && this.m_selToken != null) { if(m_logger.isDebugEnabled()) { m_logger.debug("Login for: " + this.m_selToken.getCertName() + " id: " + this.m_selToken.getIdHex()); } try { this.m_currentSession.login(true, pin.toCharArray()); } catch (PKCS11Exception var4) { m_logger.error("Pkcs11 error: " + var4); if(var4.getErrorCode() == 256L) { m_logger.error("User already logged in ok"); } else { DigiDocException.handleException(var4, 60); } } } } catch (TokenException var5) { this.m_selToken = null; this.m_currentSession = null; DigiDocException.handleException(var5, 60); } } public void openSession(boolean bSignSession, int token, String pin) throws DigiDocException { if(this.m_pkcs11Module == null) { this.initPKCS11(); } try { if(this.m_currentSession == null || this.m_selToken == null || bSignSession && !this.m_selToken.isSignatureKey() || !bSignSession && this.m_selToken.isSignatureKey()) { if(this.m_currentSession != null) { this.closeSession(); } if(m_logger.isDebugEnabled()) { m_logger.debug("Open session for token: " + token); } TokenKeyInfo e = null; TokenKeyInfo[] tkis = this.getTokensOfType(bSignSession); if(token >= 0 && tkis != null && token < tkis.length) { e = tkis[token]; } if(m_logger.isDebugEnabled()) { m_logger.debug("Open " + (bSignSession?"sign":"auth") + " session for: " + (e != null?e.getCertName() + " id: " + e.getIdHex() + " sign: " + e.isSignatureKey() + " crypt: " + e.isEncryptKey():"NULL")); } if(e != null) { this.m_currentSession = e.getToken().openSession(true, false, (Object)null, (Notify)null); this.m_selToken = e; } else if(m_logger.isDebugEnabled()) { m_logger.debug("No suitable token found!"); } if(this.m_currentSession != null && this.m_selToken != null) { if(m_logger.isDebugEnabled()) { m_logger.debug("Login for: " + this.m_selToken.getCertName() + " id: " + this.m_selToken.getIdHex()); } try { this.m_currentSession.login(true, pin.toCharArray()); } catch (PKCS11Exception var7) { m_logger.error("Pkcs11 error: " + var7); if(var7.getErrorCode() == 256L) { m_logger.error("User already logged in ok"); } else { DigiDocException.handleException(var7, 60); } } } } } catch (TokenException var8) { this.m_selToken = null; this.m_currentSession = null; DigiDocException.handleException(var8, 60); } } public byte[] sign(byte[] digest, int token, String pin, Signature sig) throws DigiDocException { byte[] sigVal = null; if(this.m_currentSession == null) { this.openSession(true, token, pin); } try { if(m_logger.isDebugEnabled()) { m_logger.debug("Sign with token: " + token + " key: " + (this.m_selToken != null?this.m_selToken.getCertName():"NULL") + " id: " + (this.m_selToken != null?this.m_selToken.getIdHex():"NULL") + " dig-len: " + (digest != null?digest.length:0) + " dig: " + (digest != null?Base64Util.encode(digest):"NULL")); } RSAPrivateKey e = new RSAPrivateKey(); this.m_currentSession.findObjectsInit(e); iaik.pkcs.pkcs11.objects.Object[] keys = null; RSAPrivateKey sigKey = null; boolean bFound = false; do { keys = this.m_currentSession.findObjects(1); if(keys != null && keys.length > 0) { for(int i = 0; !bFound && i < keys.length; ++i) { sigKey = (RSAPrivateKey)keys[i]; String keyIdHex = SignedDoc.bin2hex(sigKey.getId().getByteArrayValue()); if(m_logger.isDebugEnabled()) { m_logger.debug("Key " + i + " id: " + keyIdHex); } if(keyIdHex != null && this.m_selToken.getIdHex() != null && keyIdHex.equals(this.m_selToken.getIdHex())) { if(m_logger.isDebugEnabled()) { m_logger.debug("Using key " + i + " id: " + keyIdHex); } Mechanism sigMech = Mechanism.RSA_PKCS; this.m_currentSession.signInit(sigMech, sigKey); byte[] ddata = ConvertUtils.addDigestAsn1Prefix(digest); sigVal = this.m_currentSession.sign(ddata); if(m_logger.isDebugEnabled()) { m_logger.debug("Signature len: " + (sigVal != null?sigVal.length:0)); } break; } } } } while(!bFound && keys != null && keys.length > 0); this.m_currentSession.findObjectsFinal(); this.closeSession(); } catch (TokenException var14) { DigiDocException.handleException(var14, 61); } return sigVal; } public byte[] sign(byte[] digest, long nSlotId, String certLabel, String pin, Signature sig) throws DigiDocException { byte[] sigVal = null; TokenKeyInfo tki = this.getTokenWithSlotIdAndLabel(nSlotId, certLabel); if(tki == null) { m_logger.error("No token with slot: " + nSlotId + " and label: " + certLabel + " found!"); return null; } else { if(this.m_currentSession == null) { this.openSession(tki, pin); } try { if(m_logger.isDebugEnabled()) { m_logger.debug("Sign with token: " + tki + " key: " + (this.m_selToken != null?this.m_selToken.getCertName():"NULL") + " id: " + (this.m_selToken != null?this.m_selToken.getIdHex():"NULL") + " dig-len: " + (digest != null?digest.length:0) + " dig: " + (digest != null?Base64Util.encode(digest):"NULL")); } RSAPrivateKey e = new RSAPrivateKey(); this.m_currentSession.findObjectsInit(e); iaik.pkcs.pkcs11.objects.Object[] foundKeys = null; boolean bFound = false; do { foundKeys = this.m_currentSession.findObjects(1); if(foundKeys != null && foundKeys.length > 0) { RSAPrivateKey sigKey = null; if(m_logger.isDebugEnabled()) { m_logger.debug("Keys: " + foundKeys.length); } for(int i = 0; !bFound && i < foundKeys.length; ++i) { sigKey = (RSAPrivateKey)foundKeys[i]; String keyLabel = null; if(sigKey.getLabel() != null) { keyLabel = sigKey.getLabel().toString(); if(m_logger.isDebugEnabled()) { m_logger.debug("Key " + i + " label: " + keyLabel); } } if(keyLabel != null && this.m_selToken.getLabel() != null && keyLabel.equals(this.m_selToken.getLabel())) { if(m_logger.isDebugEnabled()) { m_logger.debug("Using key " + i + " label: " + keyLabel); } bFound = true; Mechanism sigMech = Mechanism.RSA_PKCS; this.m_currentSession.signInit(sigMech, sigKey); byte[] ddata = ConvertUtils.addDigestAsn1Prefix(digest); sigVal = this.m_currentSession.sign(ddata); if(m_logger.isDebugEnabled()) { m_logger.debug("Signature len: " + (sigVal != null?sigVal.length:0)); } break; } } } } while(!bFound && foundKeys != null && foundKeys.length > 0); if(!bFound) { m_logger.error("Failed to sign, token with slot: " + nSlotId + " and label: " + certLabel + " not found!"); } this.m_currentSession.findObjectsFinal(); this.closeSession(); } catch (TokenException var17) { DigiDocException.handleException(var17, 61); } return sigVal; } } public X509Certificate getCertificate(int token, String pin) throws DigiDocException { if(m_logger.isDebugEnabled()) { m_logger.debug("Get cert in slot: " + token); } if(this.m_currentSession == null) { this.openSession(true, token, pin); } if(m_logger.isDebugEnabled()) { m_logger.debug("Got cert in slot: " + token + " nr: " + this.m_selToken.getNr() + " sign: " + this.m_selToken.isSignatureKey() + " enc: " + this.m_selToken.isEncryptKey()); } return this.m_selToken != null?this.m_selToken.getCert():null; } public X509Certificate getAuthCertificate(int token, String pin) throws DigiDocException { if(this.m_currentSession == null) { this.openSession(false, token, pin); } if(m_logger.isDebugEnabled()) { m_logger.debug("Get cert for token: " + token); } return this.m_selToken != null?this.m_selToken.getCert():null; } public byte[] decrypt(byte[] data, int token, String pin) throws DigiDocException { byte[] value = null; if(this.m_currentSession == null) { this.openSession(false, token, pin); } try { if(m_logger.isDebugEnabled()) { m_logger.debug("Decrypting " + data.length + " bytes"); m_logger.debug("Decrypting with token: " + this.m_selToken.getNr()); m_logger.debug("session: " + this.m_currentSession); } RSAPrivateKey e = new RSAPrivateKey(); this.m_currentSession.findObjectsInit(e); iaik.pkcs.pkcs11.objects.Object[] keys = null; boolean bFound = false; do { keys = this.m_currentSession.findObjects(1); if(keys != null && keys.length > 0) { RSAPrivateKey key = null; for(int i = 0; !bFound && i < keys.length; ++i) { key = (RSAPrivateKey)keys[i]; String keyIdHex = null; if(key.getId() != null) { keyIdHex = SignedDoc.bin2hex(key.getId().getByteArrayValue()); if(m_logger.isDebugEnabled()) { m_logger.debug("Key " + i + " id: " + keyIdHex); } } if(keyIdHex != null && this.m_selToken.getIdHex() != null && keyIdHex.equals(this.m_selToken.getIdHex())) { bFound = true; if(m_logger.isDebugEnabled()) { m_logger.debug("Using key " + i + " id: " + keyIdHex); } Mechanism m = Mechanism.RSA_PKCS; this.m_currentSession.decryptInit(m, key); if(m_logger.isDebugEnabled()) { m_logger.debug("decryptInit OK"); } value = this.m_currentSession.decrypt(data); if(m_logger.isDebugEnabled()) { m_logger.debug("value = " + value); } break; } } } } while(!bFound && keys != null && keys.length > 0); if(m_logger.isInfoEnabled()) { m_logger.info("Decrypted " + (data != null?data.length:0) + " bytes, got: " + value.length); } this.m_currentSession.findObjectsFinal(); this.closeSession(); } catch (TokenException var12) { DigiDocException.handleException(var12, 111); } return value; } public byte[] decrypt(byte[] data, long slot, String label, String pin) throws DigiDocException { byte[] value = null; TokenKeyInfo tki = this.getTokenWithSlotIdAndLabel(slot, label); if(tki == null) { m_logger.error("No token with slot: " + slot + " and label: " + label + " found!"); return null; } else { if(this.m_currentSession == null) { this.openSession(tki, pin); } try { RSAPrivateKey e = new RSAPrivateKey(); this.m_currentSession.findObjectsInit(e); if(m_logger.isDebugEnabled()) { m_logger.debug("Decrypting " + data.length + " bytes"); m_logger.debug("Decrypting with token: " + this.m_selToken.getNr()); m_logger.debug("session: " + this.m_currentSession); } RSAPrivateKey key = null; boolean bFound = false; iaik.pkcs.pkcs11.objects.Object[] keys = null; do { keys = this.m_currentSession.findObjects(1); if(keys != null && keys.length > 0) { for(int i = 0; !bFound && i < keys.length; ++i) { key = (RSAPrivateKey)keys[i]; String keyLabel = null; if(key.getLabel() != null) { keyLabel = key.getLabel().toString(); if(m_logger.isDebugEnabled()) { m_logger.debug("Key " + i + " label: " + keyLabel); } } if(keyLabel != null && this.m_selToken.getLabel() != null && keyLabel.equals(this.m_selToken.getLabel())) { if(m_logger.isDebugEnabled()) { m_logger.debug("Using key " + i + " label: " + keyLabel); } bFound = true; Mechanism m = Mechanism.RSA_PKCS; this.m_currentSession.decryptInit(m, key); if(m_logger.isDebugEnabled()) { m_logger.debug("decryptInit OK"); } value = this.m_currentSession.decrypt(data); if(m_logger.isDebugEnabled()) { m_logger.debug("value = " + value); } break; } } } } while(!bFound && keys != null && keys.length > 0); if(!bFound) { m_logger.error("Failed to sign, token with slot: " + slot + " and label: " + label + " not found!"); } if(m_logger.isInfoEnabled()) { m_logger.info("Decrypted " + (data != null?data.length:0) + " bytes, got: " + value.length); } this.m_currentSession.findObjectsFinal(); this.closeSession(); } catch (TokenException var15) { DigiDocException.handleException(var15, 111); } return value; } } public void closeSession() throws DigiDocException { try { if(m_logger.isDebugEnabled()) { m_logger.debug("Closing card session"); } if(this.m_currentSession != null) { this.m_currentSession.closeSession(); } this.m_currentSession = null; } catch (TokenException var2) { DigiDocException.handleException(var2, 63); } } public void finalize() throws DigiDocException { try { if(this.m_pkcs11Module != null) { this.m_pkcs11Module.finalize((Object)null); } m_isInitialized = false; this.m_pkcs11Module = null; } catch (TokenException var2) { DigiDocException.handleException(var2, 64); } } public void reset() throws DigiDocException { if(m_logger.isDebugEnabled()) { m_logger.debug("Resetting PKCS11SignatureFactory"); } this.m_selToken = null; this.closeSession(); m_isInitialized = false; this.m_pkcs11Module = null; this.m_secProvider = null; this.finalize(); } public String getType() { return "PKCS11"; } }