I work with the brazilian \"Nota Fiscal Eletronica\" project, in which they define a standart way to sign XML documents.
Recently, they started to require that there
Fortunately XMLSignature is opensource, so I guess you'll have to get the source code and hack it your self.
Probably your solution will help others in the future so, create a patch and send it back to the project.
Good luck!
:) :)
I found a (shameful) solution.
It's not the expected solution, though: replacing apache's API with javax.xml.crypto API.
Here's the changed code:
// the element where to insert the signature
Element element = ...;
X509Certificate cert = ...;
PrivateKey privateKey = ...;
// Create a DOM XMLSignatureFactory that will be used to
// generate the enveloped signature.
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
// Create a Reference to the enveloped document (in this case,
// you are signing the whole document, so a URI of "" signifies
// that, and also specify the SHA1 digest algorithm and
// the ENVELOPED Transform.
List<Transform> transformList = new ArrayList<Transform>();
TransformParameterSpec tps = null;
Transform envelopedTransform;
try {
envelopedTransform = fac.newTransform(Transform.ENVELOPED,
tps);
Transform c14NTransform = fac.newTransform(
"http://www.w3.org/TR/2001/REC-xml-c14n-20010315", tps);
transformList.add(envelopedTransform);
transformList.add(c14NTransform);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Erro inesperado: " + e.getMessage(), e);
} catch (InvalidAlgorithmParameterException e) {
throw new RuntimeException("Erro inesperado: " + e.getMessage(), e);
}
// Create the KeyInfo containing the X509Data.
KeyInfoFactory kif = fac.getKeyInfoFactory();
List<Serializable> x509Content = new ArrayList<Serializable>();
x509Content.add(cert);
javax.xml.crypto.dsig.keyinfo.X509Data xd = kif.newX509Data(x509Content);
KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));
// Obtem elemento do documento a ser assinado, será criado uma
// REFERENCE para o mesmo
Element el = (Element) element.getElementsByTagName(subTag).item(0);
String id = el.getAttribute("Id");
// Create a DOM XMLSignatureFactory that will be used to
// generate the enveloped signature.
Reference ref;
javax.xml.crypto.dsig.SignedInfo si;
try {
ref = fac.newReference("#" + id, fac.newDigestMethod(
DigestMethod.SHA1, null), transformList, null, null);
// Create the SignedInfo.
si = fac.newSignedInfo(fac.newCanonicalizationMethod(
CanonicalizationMethod.INCLUSIVE,
(C14NMethodParameterSpec) null), fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
Collections.singletonList(ref));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Erro inesperado: " + e.getMessage(), e);
} catch (InvalidAlgorithmParameterException e) {
throw new RuntimeException("Erro inesperado: " + e.getMessage(), e);
}
// Create the XMLSignature, but don't sign it yet.
javax.xml.crypto.dsig.XMLSignature signature = fac.newXMLSignature(si, ki);
// Marshal, generate, and sign the enveloped signature.
// Create a DOMSignContext and specify the RSA PrivateKey and
// location of the resulting XMLSignature's parent element.
DOMSignContext dsc = new DOMSignContext(privateKey, element);
signature.sign(dsc);
This API produces the signature with no whitespaces between tags at all.
Still would like to see a solution for apache's API, since this code was very mature already, and we wouldn't like to risk as much as changing the entire signature implementation.
You can simply set -Dorg.apache.xml.security.ignoreLineBreaks=true for disabling '\n' in XML generation. original mail
bug description
You can try:
System.setProperty("org.apache.xml.security.ignoreLineBreaks", "true");
You can try:
static {
System.setProperty("com.sun.org.apache.xml.internal.security.ignoreLineBreaks", "true");
com.sun.org.apache.xml.internal.security.Init.init();
}
Or
static {
System.setProperty("org.apache.xml.security.ignoreLineBreaks", "true");
org.apache.xml.security.Init.init();
}
Add this to the class which does signature job.
the signature blocks are encoding binary information as Base64, which must follow some formating including line breaks (see http://en.wikipedia.org/wiki/Base64). So you simply can't remove them without alter the information.
a better way to redure network traffic, is to use comression before sending data.