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";
}
}