All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
ee.sk.digidoc.factory.Pkcs12SignatureFactory Maven / Gradle / Ivy
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.utils.ConfigManager;
import ee.sk.utils.ConvertUtils;
import java.security.cert.X509Certificate;
import java.security.interfaces.ECPrivateKey;
import java.security.*;
import java.io.*;
import java.util.*;
import javax.crypto.Cipher;
import org.apache.log4j.Logger;
/**
* PKCS#12 based signature implementation
* @author Veiko Sinivee
* @version 1.0
*/
public class Pkcs12SignatureFactory
implements SignatureFactory
{
private KeyStore m_keyStore;
/** log4j logger */
private static Logger m_logger = Logger.getLogger(Pkcs12SignatureFactory.class);
/** security provider */
private Provider m_secProvider;
/**
* initializes the implementation class
*/
public void init()
throws DigiDocException
{
initProvider();
if(m_keyStore == null) {
ConfigManager cfg = ConfigManager.instance();
String storeFile = cfg.getProperty("DIGIDOC_KEYSTORE_FILE");
String storeType = cfg.getProperty("DIGIDOC_KEYSTORE_TYPE");
String storePasswd = cfg.getProperty("DIGIDOC_KEYSTORE_PASSWD");
if(storeFile != null && storeType != null && storePasswd != null)
load(storeFile, storeType, storePasswd);
}
}
public boolean load(String storeName, String storeType, String passwd)
throws DigiDocException
{
FileInputStream fis = null;
try {
if(m_logger.isDebugEnabled())
m_logger.debug("Load store: " + storeName + " type: " + storeType);
m_keyStore = KeyStore.getInstance(storeType);
if(m_keyStore != null) {
m_keyStore.load(fis = new FileInputStream(storeName), passwd.toCharArray());
return true;
}
} catch(Exception ex) {
m_logger.error("Error loading store: " + storeName + " - " + ex);
} finally {
if(fis != null) {
try {
fis.close();
fis = null;
} catch(Exception ex2) {
m_logger.error("Error closing pkcs12: " + storeName + " - " + ex2);
}
}
}
return false;
}
/**
* Initializes Java cryptography provider
*/
private void initProvider()
throws DigiDocException
{
try {
m_secProvider = (Provider)Class.forName(ConfigManager.
instance().getProperty("DIGIDOC_SECURITY_PROVIDER")).newInstance();
Security.addProvider(m_secProvider);
} catch(Exception ex) {
m_secProvider = null;
DigiDocException.handleException(ex, DigiDocException.ERR_CRYPTO_PROVIDER);
}
}
/**
* Reads all useable token keys
* @return list of available token/key info
* @throws DigiDocException
*/
public TokenKeyInfo[] getTokenKeys()
throws DigiDocException
{
return null;
}
/**
* Finds keys of specific type
* @param bSign true if searching signature keys
* @return array of key infos
*/
public TokenKeyInfo[] getTokensOfType(boolean bSign)
{
return null;
}
/**
* Method returns an array of strings representing the
* list of available token names.
* @return an array of available token names.
* @throws DigiDocException if reading the token information fails.
*/
public String[] getAvailableTokenNames()
throws DigiDocException
{
Vector vec = new Vector();
try {
if(m_keyStore != null) {
Enumeration eAliases = m_keyStore.aliases();
while(eAliases.hasMoreElements()) {
String alias = (String)eAliases.nextElement();
vec.add(alias);
}
}
} catch(Exception ex) {
m_logger.error("Error reading store aliases: " + ex);
}
String[] arr = new String[vec.size()];
for(int i = 0; (vec != null) && (i < vec.size()); i++)
arr[i] = (String)vec.elementAt(i);
return arr;
}
/**
* Returns the n-th token name or alias
* @param nIdx index of token
* @return alias
*/
private String getTokenName(int nIdx)
{
try {
if(m_keyStore != null) {
Enumeration eAliases = m_keyStore.aliases();
for(int i = 0; eAliases.hasMoreElements(); i++) {
String alias = (String)eAliases.nextElement();
if(i == nIdx)
return alias;
}
}
} catch(Exception ex) {
m_logger.error("Error reading store aliases: " + ex);
}
return null;
}
public static java.security.Signature sigMeth2SigSignatureInstance(Signature sig, Key key)
throws DigiDocException
{
java.security.Signature instance = null;
String sigMeth = null, sigType = null;
try {
if(sig != null && sig.getSignedInfo() != null && sig.getSignedInfo().getSignatureMethod() != null)
sigMeth = sig.getSignedInfo().getSignatureMethod();
sigType = ConfigManager.instance().sigMeth2SigType(sigMeth, true); // allways use cvc ciphers
if(m_logger.isDebugEnabled())
m_logger.debug("Key: " + ((key != null) ? "OK, algorithm: " + key.getAlgorithm() : "NULL") + " method: " + sigMeth + " type: " + sigType);
if(sigType == null)
throw new DigiDocException(DigiDocException.ERR_SIGNATURE_METHOD, "SignatureMethod not specified!", null);
instance = java.security.Signature.getInstance(sigType, ConfigManager.addProvider());
} catch(Exception ex) {
m_logger.error("Error constructing signature instance: " + ex);
}
return instance;
}
private boolean isCvcEcKey(Signature sig)
{
String sigMeth = sig.getSignedInfo().getSignatureMethod();
String sSigType = ConfigManager.instance().sigMeth2SigType(sigMeth, true);
return ConfigManager.isEcdsaCvcAlgorithm(sSigType);
}
/**
* Method returns a digital signature. It finds the RSA private
* key object from the active token and
* then signs the given data with this key and RSA mechanism.
* @param digest digest of the data to be signed.
* @param token token index
* @param passwd users pin code or in case of pkcs12 file password
* @param sig Signature object to provide info about desired signature method
* @return an array of bytes containing digital signature.
* @throws DigiDocException if signing the data fails.
*/
public byte[] sign(byte[] xml, int token, String passwd, Signature sig)
throws DigiDocException
{
try {
if(m_keyStore == null)
throw new DigiDocException(DigiDocException.ERR_NOT_INITED, "Keystore not initialized", null);
String alias = getTokenName(token);
if(alias == null)
throw new DigiDocException(DigiDocException.ERR_TOKEN_LOGIN, "Invalid token nr: " + token, null);
// get key
if(m_logger.isDebugEnabled())
m_logger.debug("loading key: " + alias + " passwd-len: " + ((passwd != null) ? passwd.length() : 0));
Key key = m_keyStore.getKey(alias, passwd.toCharArray());
if(m_logger.isDebugEnabled())
m_logger.debug("Key: " + ((key != null) ? "OK, algorithm: " + key.getAlgorithm() : "NULL"));
if(key == null)
throw new DigiDocException(DigiDocException.ERR_TOKEN_LOGIN, "Invalid password for token nr: " + token, null);
String sigMeth = null;
if(sig != null && sig.getSignedInfo() != null && sig.getSignedInfo().getSignatureMethod() != null)
sigMeth = sig.getSignedInfo().getSignatureMethod();
if(m_logger.isDebugEnabled())
m_logger.debug("Signing\n---\n" + new String(xml) + "\n---\n method: " + sigMeth);
java.security.Signature instance = sigMeth2SigSignatureInstance(sig, key);
if(m_logger.isDebugEnabled())
m_logger.debug("Signature instance: " + ((instance != null) ? "OK" : "NULL"));
instance.initSign((PrivateKey)key);
instance.update(xml);
byte[] signature = instance.sign();
boolean bEcCvcKey = isCvcEcKey(sig);
if(m_logger.isDebugEnabled())
m_logger.debug("Signature algorithm: " + key.getAlgorithm() + " siglen: " + signature.length + " ec-key: " + bEcCvcKey);
if(bEcCvcKey) {
int nKeyLen = ((ECPrivateKey)key).getParams().getCurve().getField().getFieldSize();
int nReqLen = ((int) Math.ceil((double) nKeyLen / 8)) * 2;
int nSigLen = signature.length;
if(m_logger.isDebugEnabled())
m_logger.debug("EC Signature length: " + nSigLen + " required: " + nReqLen);
if(nSigLen < nReqLen) {
if(m_logger.isDebugEnabled())
m_logger.debug("Padding EC signature length: " + nSigLen + " to required: " + nReqLen);
byte[] padsig = new byte[nReqLen];
System.arraycopy(signature, 0, padsig, (nReqLen - nSigLen) / 2, nSigLen / 2);
System.arraycopy(signature, nSigLen / 2, padsig, (nReqLen / 2) + (nReqLen - nSigLen) / 2, nSigLen / 2);
signature = padsig;
}
}
if(m_logger.isDebugEnabled() && signature != null)
m_logger.debug("Signature len: " + signature.length + "\n---\n sig: " + ConvertUtils.bin2hex(signature));
return signature;
} catch(DigiDocException ex) {
m_logger.error("DigiDoc Error signing: " + ex);
throw ex;
} catch(Exception ex) {
m_logger.error("Error signing: " + ex);
}
return null;
}
/**
* Method returns a X.509 certificate object readed
* from the active token and representing an
* user public key certificate value.
* @return X.509 certificate object.
* @throws DigiDocException if getting X.509 public key certificate
* fails or the requested certificate type X.509 is not available in
* the default provider package
*/
public X509Certificate getCertificate(int token, String pin)
throws DigiDocException
{
if(m_keyStore == null)
throw new DigiDocException(DigiDocException.ERR_NOT_INITED, "Keystore not initialized", null);
String alias = getTokenName(token);
if(alias == null)
throw new DigiDocException(DigiDocException.ERR_TOKEN_LOGIN, "Invalid token nr: " + token, null);
try {
return (X509Certificate)m_keyStore.getCertificate(alias);
} catch(Exception ex) {
m_logger.error("Error reading cert for alias: " + alias + " - " + ex);
}
return null;
}
/**
* Method returns a X.509 certificate object readed
* from the active token and representing an
* user public key certificate value.
* @return X.509 certificate object.
* @throws DigiDocException if getting X.509 public key certificate
* fails or the requested certificate type X.509 is not available in
* the default provider package
*/
public X509Certificate getAuthCertificate(int token, String pin)
throws DigiDocException
{
return getCertificate(token, pin);
}
/**
* Resets the previous session
* and other selected values
*/
public void reset()
throws DigiDocException
{
m_keyStore = null;
}
/**
* Method closes the current session.
* @throws DigiDocException if closing the session fails.
*/
public void closeSession()
throws DigiDocException
{
reset();
}
/**
* Method decrypts the data with the RSA private key
* corresponding to this certificate (which was used
* to encrypt it). Decryption will be done with keystore
* @param data data to be decrypted.
* @param token index of authentication token
* @param pin PIN code
* @return decrypted data.
* @throws DigiDocException for all decryption errors
*/
public byte[] decrypt(byte[] data, int token, String pin)
throws DigiDocException
{
try {
if(m_keyStore == null)
throw new DigiDocException(DigiDocException.ERR_NOT_INITED, "Keystore not initialized", null);
String alias = getTokenName(token);
if(alias == null)
throw new DigiDocException(DigiDocException.ERR_TOKEN_LOGIN, "Invalid token nr: " + token, null);
// get key
if(m_logger.isDebugEnabled())
m_logger.debug("loading key: " + alias + " passwd-len: " + ((pin != null) ? pin.length() : 0));
Key key = m_keyStore.getKey(alias, pin.toCharArray());
if(m_logger.isDebugEnabled())
m_logger.debug("Key: " + ((key != null) ? "OK, algorithm: " + key.getAlgorithm() : "NULL"));
if(key == null)
throw new DigiDocException(DigiDocException.ERR_TOKEN_LOGIN, "Invalid password for token: " + alias, null);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decdata = cipher.doFinal(data);
if(m_logger.isDebugEnabled())
m_logger.debug("Decrypted len: " + ((decdata != null) ? decdata.length : 0));
return decdata;
} catch(Exception ex) {
m_logger.error("Error decrypting: " + ex);
}
return null;
}
/**
* Returns signature factory type identifier
* @return factory type identifier
*/
public String getType()
{
return SIGFAC_TYPE_PKCS12;
}
}