package es.uji.security.crypto.jxades;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.security.Provider;
import java.security.Security;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.dsig.DigestMethod;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.Transform;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureException;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.spec.XPathFilterParameterSpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import net.java.xades.security.xml.XAdES.SignaturePolicyIdentifier;
import net.java.xades.security.xml.XAdES.SignaturePolicyIdentifierImpl;
import net.java.xades.security.xml.XAdES.SignerRole;
import net.java.xades.security.xml.XAdES.SignerRoleImpl;
import net.java.xades.security.xml.XAdES.XAdES;
import net.java.xades.security.xml.XAdES.XAdES_EPES;
import net.java.xades.security.xml.XAdES.XMLAdvancedSignature;
import net.java.xades.util.XMLUtils;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import es.uji.security.crypto.ISignFormatProvider;
import es.uji.security.crypto.SignatureOptions;
import es.uji.security.crypto.SignatureResult;
import es.uji.security.crypto.config.ConfigManager;
import es.uji.security.crypto.config.OS;
import es.uji.security.util.i18n.LabelManager;
public class JXAdESSignatureFactory implements ISignFormatProvider
{
public SignatureResult formatSignature(SignatureOptions signatureOptions) throws Exception
{
byte[] data = OS.inputStreamToByteArray(signatureOptions.getDataToSign());
X509Certificate certificate = signatureOptions.getCertificate();
PrivateKey privateKey = signatureOptions.getPrivateKey();
Provider provider = signatureOptions.getProvider();
//TODO: KeyStore loaded in device init must store the reference
// Security.removeProvider(provider.getName());
// Security.insertProviderAt(provider, 1);
ByteArrayInputStream originalData = new ByteArrayInputStream(data);
SignatureResult signatureResult = new SignatureResult();
if (certificate == null)
{
signatureResult.setValid(false);
signatureResult.addError(LabelManager.get("ERROR_FACTURAE_NOCERT"));
return signatureResult;
}
if (privateKey == null)
{
signatureResult.setValid(false);
signatureResult.addError(LabelManager.get("ERROR_FACTURAE_NOKEY"));
return signatureResult;
}
XAdES_EPES xades = null;
Element element = null;
if (signatureOptions.isDetached())
{
xades = (XAdES_EPES) XAdES.newInstance(XAdES.EPES);
}
else
{
// Load XML data
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
element = db.parse(originalData).getDocumentElement();
// Create a XAdES-EPES profile
xades = (XAdES_EPES) XAdES.newInstance(XAdES.EPES, element);
}
// SigningCertificate. Check the certificate validity (local)
try
{
certificate.checkValidity();
}
catch (CertificateException cex)
{
signatureResult.setValid(false);
signatureResult.addError(LabelManager.get("ERROR_CERTIFICATE_EXPIRED"));
return signatureResult;
}
xades.setSigningCertificate(certificate);
SignaturePolicyIdentifier spi;
if (signatureOptions.getPolicyIdentifier() != null)
{
spi = new SignaturePolicyIdentifierImpl(false);
spi.setIdentifier(signatureOptions.getPolicyIdentifier());
spi.setDescription(signatureOptions.getPolicyDescription());
xades.setSignaturePolicyIdentifier(spi);
}
if (signatureOptions.getSignerRole() != null)
{
SignerRole role = new SignerRoleImpl();
role.setClaimedRole(new ArrayList<String>(Arrays.asList(new String[] { signatureOptions
.getSignerRole() })));
xades.setSignerRole(role);
}
ConfigManager conf = ConfigManager.getInstance();
int tsaCount = conf.getIntProperty("DIGIDOC_TSA_COUNT", 0);
String tsaUrl = null;
if (tsaCount != 0)
{
tsaUrl = conf.getProperty("DIGIDOC_TSA1_URL");
}
// Sign data
XMLAdvancedSignature xmlSignature = XMLAdvancedSignature.newInstance(xades);
try
{
// If detached
if (signatureOptions.isDetached())
{
xmlSignature.sign(certificate, privateKey, SignatureMethod.RSA_SHA1, Arrays
.asList(new Object[] { signatureOptions.getReferences().get(0) }), "S0");
}
// If enveloped+cosig construct special transformation
else
{
NodeList result = element.getElementsByTagNameNS("http://www.w3.org/2000/09/xmldsig#",
"Signature");
int numSignature = result.getLength();
List<String> references = signatureOptions.getReferences();
// If no there are no references, add enveloped reference
if (signatureOptions.isEnveloped() || references.isEmpty())
{
references.clear();
references.add("");
}
if (signatureOptions.isEnveloped() && signatureOptions.isCoSignEnabled())
{
XMLSignatureFactory xmlSignatureFactory = XMLSignatureFactory.getInstance("DOM");
DigestMethod digestMethod = xmlSignatureFactory.newDigestMethod(DigestMethod.SHA1,
null);
Transform transform = xmlSignatureFactory.newTransform(Transform.XPATH,
new XPathFilterParameterSpec("not(ancestor-or-self::dsig:Signature)",
Collections.singletonMap("dsig", XMLSignature.XMLNS)));
Reference reference = xmlSignatureFactory.newReference("", digestMethod,
Collections.singletonList(transform), null, null);
xmlSignature.sign(certificate, privateKey, SignatureMethod.RSA_SHA1, Arrays
.asList(new Object[] { reference }), "S" + numSignature);
}
else
{
xmlSignature.sign(certificate, privateKey, SignatureMethod.RSA_SHA1, references,
"S" + numSignature);
}
}
}
catch (MarshalException me)
{
signatureResult.setValid(false);
signatureResult.addError(LabelManager.get("ERROR_FACTURAE_SIGNATURE"));
return signatureResult;
}
catch (XMLSignatureException xmlse)
{
signatureResult.setValid(false);
signatureResult.addError(LabelManager.get("ERROR_FACTURAE_SIGNATURE"));
return signatureResult;
}
catch (GeneralSecurityException gse)
{
signatureResult.setValid(false);
signatureResult.addError(LabelManager.get("ERROR_FACTURAE_SIGNATURE"));
return signatureResult;
}
// Return Results
ByteArrayOutputStream out = new ByteArrayOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(out);
if (signatureOptions.isDetached())
{
XMLUtils.writeXML(bos, xmlSignature.getBaseDocument(), false);
}
else
{
XMLUtils.writeXML(bos, xmlSignature.getBaseElement(), false);
}
bos.flush();
signatureResult.setValid(true);
signatureResult.setSignatureData(new ByteArrayInputStream(out.toByteArray()));
return signatureResult;
}
}