I have got xades XML as InputStream. I do not care if certyficates are valid, check sign, etc. I can't provide any CA or any other type of certificate storage/validation. What I need is just get documents embedded in xades file as streams or temporary files on disk so I can process them as they were plain files from disk. Could someone provide snippet that extracts embedded documents? TIA
Asked
Active
Viewed 2,365 times
2
-
What have you tried so far? Can you post some code, and more detail on what you're trying to do? It's difficult to determine how to help otherwise. – Chris Mantle Jul 03 '13 at 14:06
-
I do not know how to start. I know I have to unmarshall the XML first, but does xades4j provide interface for that? Do I have to parse the XML by myself? I am totally green... – redguy Jul 03 '13 at 15:12
-
ok. I found some code here: https://code.google.com/p/xades4j/issues/detail?id=37 which points me to use DocumentBuilderFactory and DocumentBuilder to parse xml file. I will follow this trail. – redguy Jul 03 '13 at 20:47
-
so far I can get Document object which is plain XML node object in fact... how to get SignedInfo object (I guess I need it to fetch embedded files data)? In test/examples I have found I must provide digest/sign algorithms, certyficate types, etc - I do not have information about them. I want to open provided xades file and just get contents. Any help? – redguy Jul 04 '13 at 08:53
-
Sorry, I'm not familiar with xades4j - I just reviewed your post. If you're just reading in and then extracting some elements from plain XML, without having xades4j validate it or anything, I'd suggest using [XOM](http://www.xom.nu/tutorial.xhtml) instead of the built-in XML parsing (DocumentBuilderFactory, DocumentBuilder, etc.). I found it *much* easier to work with. Look at the 'Parsing XML Documents' and 'Navigation' sections in the link above. Don't worry about validation or SAX. Hopefully that helps. – Chris Mantle Jul 04 '13 at 14:04
-
thanks for info, but xades is something more than xml. xml is only representation of some signed documents, digest, certs, etc. I know how to parse XML, but I need to pass it through xades library so I am sure I will get embedded documents raw data... is there anyone who knows how to handle xades files? – redguy Jul 04 '13 at 14:35
-
Where are the signed documents located inside the signature? In a ds:Object or ds:References to external documents? Are they also XML or something encoded in base64? From what you've said so far it seems that you really just need to parse XML. In the xades4j code you can find some JAXB classes that reflect the XAdES schema. Maybe using JAXB could help you on unmarshalling. – lgoncalves Jul 05 '13 at 20:20
-
they are in ds:Object tags. You can see example file under: http://www.monitorpolski.gov.pl/mp/2009/s/73/920/M2009073092001.xades (it is Polish government official papers site) – redguy Jul 09 '13 at 11:46
-
anyone knows how to do this? – redguy Jul 15 '13 at 13:27
1 Answers
2
To extract Base64-encoded signed content from XAdES signed file i use code like below. It doesn't use xades4j at all.
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import org.bouncycastle.util.encoders.Base64;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class Utils {
/**
* extract ds:Object from .xades file
*
* @param xadesIn .xades file input stream
* @return base64 decoded bytes
* @throws Exception
*/
public static byte[] extractContentFromXadesSignedFile(InputStream xadesIn) throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document doc = dbf.newDocumentBuilder().parse(xadesIn);
xadesIn.close();
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
xpath.setNamespaceContext(new SimpleNamespaceContext(new HashMap<String, String>() {{
put("ds", "http://www.w3.org/2000/09/xmldsig#");
}}));
XPathExpression expr = xpath.compile("//ds:SignedInfo/ds:Reference");
NodeList referenceNodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
/**
* loop over all Reference nodes
* i need to find Object node with Id that fits URI value of Reference
*/
for(int i=0;i<referenceNodes.getLength();i++){
Node referenceNode = referenceNodes.item(i);
NamedNodeMap attributes = referenceNode.getAttributes();
if(attributes != null) {
Node uri = attributes.getNamedItem("URI");
if(uri != null) {
String objectId = uri.getNodeValue();
XPathExpression expr2 = xpath.compile("//ds:Object[@Id='"+objectId.substring(1)+"']");
Node contentNode = (Node) expr2.evaluate(doc, XPathConstants.NODE);
if(contentNode != null) {
String base64 = contentNode.getFirstChild().getNodeValue();
return Base64.decode(base64);
}
}
}
}
return null;
}
/**
* http://stackoverflow.com/a/6392700/404395
*/
private static class SimpleNamespaceContext implements NamespaceContext {
private final Map<String, String> PREF_MAP = new HashMap<String, String>();
public SimpleNamespaceContext(final Map<String, String> prefMap) {
PREF_MAP.putAll(prefMap);
}
@Override
public String getNamespaceURI(String prefix) {
return PREF_MAP.get(prefix);
}
@Override
public String getPrefix(String uri) {
throw new UnsupportedOperationException();
}
@Override
public Iterator getPrefixes(String uri) {
throw new UnsupportedOperationException();
}
}
}
Sample usage of that:
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
import org.junit.Assert;
import org.junit.Test;
public class XadesExtractTest {
@Test
public void extract() throws Exception {
InputStream in = XadesExtractTest.class.getClassLoader().getResourceAsStream("test.xades");
byte[] bytes = Utils.extractContentFromXadesSignedFile(in);
Assert.assertNotNull(bytes);
in.close();
ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
File f = File.createTempFile("test", ".zip");
System.out.println(f.getAbsolutePath());
FileOutputStream fout = new FileOutputStream(f);
IOUtils.copy(bin, fout);
bin.close();
fout.close();
}
}

Adrian Mole
- 49,934
- 160
- 51
- 83

marioosh
- 27,328
- 49
- 143
- 192