1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package es.accv.arangi.base.mityc;
22
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.net.URL;
26 import java.security.PrivateKey;
27 import java.security.cert.X509Certificate;
28 import java.util.ArrayList;
29
30 import javax.xml.parsers.DocumentBuilder;
31 import javax.xml.parsers.DocumentBuilderFactory;
32 import javax.xml.xpath.XPath;
33 import javax.xml.xpath.XPathConstants;
34 import javax.xml.xpath.XPathExpression;
35 import javax.xml.xpath.XPathFactory;
36
37 import org.apache.log4j.Logger;
38 import org.apache.xml.security.utils.IgnoreAllErrorHandler;
39 import org.w3c.dom.Attr;
40 import org.w3c.dom.Document;
41 import org.w3c.dom.Element;
42 import org.w3c.dom.Node;
43 import org.w3c.dom.NodeList;
44 import org.xml.sax.InputSource;
45
46 import es.accv.arangi.base.exception.signature.CounterSignatureException;
47 import es.accv.arangi.base.signature.XAdESSignature;
48 import es.accv.arangi.base.util.Util;
49 import es.mityc.firmaJava.libreria.ConstantesXADES;
50 import es.mityc.firmaJava.libreria.excepciones.AddXadesException;
51 import es.mityc.firmaJava.libreria.utilidades.I18n;
52 import es.mityc.firmaJava.libreria.utilidades.NombreNodo;
53 import es.mityc.firmaJava.libreria.utilidades.UtilidadTratarNodo;
54 import es.mityc.firmaJava.libreria.xades.DataToSign;
55 import es.mityc.firmaJava.libreria.xades.FirmaXML;
56 import es.mityc.javasign.xml.refs.AbstractObjectToSign;
57 import es.mityc.javasign.xml.refs.InternObjectToSign;
58 import es.mityc.javasign.xml.refs.ObjectToSign;
59 import es.mityc.javasign.xml.refs.SignObjectToSign;
60
61
62
63
64
65
66
67 public class ContraFirmaXML{
68
69 static Logger logger = Logger.getLogger(ContraFirmaXML.class);
70
71
72
73
74
75
76
77
78
79
80
81
82
83 public static Document counterSign(X509Certificate certificadoFirma,
84 DataToSign xml, PrivateKey pk, String xadesSchema,
85 String digitalSignatureAlgorithm, URL urlTSA) throws Exception {
86
87 return counterSign(certificadoFirma, xml, null, pk, digitalSignatureAlgorithm, urlTSA, xadesSchema);
88 }
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 public static Document counterSign(X509Certificate certificadoFirma,
105 DataToSign xml, X509Certificate certificadoContraFirma, PrivateKey pk,
106 String digitalSignatureAlgorithm, URL urlTSA, String xadesSchema)
107 throws CounterSignatureException {
108
109 try {
110 Document doc = xml.getDocument();
111 if (doc == null) {
112 try {
113 InputStream is = xml.getInputStream();
114 if (is != null) {
115 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
116 dbf.setNamespaceAware(true);
117 DocumentBuilder db = dbf.newDocumentBuilder();
118 db.setErrorHandler(new IgnoreAllErrorHandler());
119 InputSource isour = new InputSource(is);
120 String encoding = xml.getXMLEncoding();
121 isour.setEncoding(encoding);
122 doc = db.parse(isour);
123 }
124 } catch (IOException ex) {
125 throw new Exception(I18n.getResource(ConstantesXADES.LIBRERIAXADES_FIRMAXML_ERROR_50));
126 }
127 }
128
129
130 Node nodePadreNodoFirmar = null;
131 if (certificadoContraFirma != null) {
132 nodePadreNodoFirmar = buscarNodoAFirmar(doc, certificadoContraFirma);
133 if(nodePadreNodoFirmar == null) {
134 logger.info(I18n.getResource(ConstantesXADES.LIBRERIAXADES_FIRMAXML_ERROR_33));
135 throw new AddXadesException(I18n.getResource(ConstantesXADES.LIBRERIAXADES_FIRMAXML_ERROR_51));
136 }
137 }
138
139 if (nodePadreNodoFirmar == null) {
140
141 NodeList list = doc.getElementsByTagNameNS(ConstantesXADES.SCHEMA_DSIG, ConstantesXADES.SIGNATURE);
142 if (list.getLength() < 1) {
143 logger.info(I18n.getResource(ConstantesXADES.LIBRERIAXADES_FIRMAXML_ERROR_33));
144 throw new AddXadesException(I18n.getResource(ConstantesXADES.LIBRERIAXADES_FIRMAXML_ERROR_51));
145 } else {
146 nodePadreNodoFirmar = list.item(list.getLength() - 1);
147 }
148 }
149 String idSignatureValue = null;
150 Element padreNodoFirmar = null;
151 if ((nodePadreNodoFirmar != null) && (nodePadreNodoFirmar.getNodeType() == Node.ELEMENT_NODE)) {
152 padreNodoFirmar = (Element)nodePadreNodoFirmar;
153 ArrayList<Element> listElements = UtilidadTratarNodo.obtenerNodos(padreNodoFirmar, 2, new NombreNodo(ConstantesXADES.SCHEMA_DSIG, ConstantesXADES.SIGNATURE_VALUE));
154 if (listElements.size() != 1) {
155
156 logger.info(I18n.getResource(ConstantesXADES.LIBRERIAXADES_FIRMAXML_ERROR_33));
157 throw new AddXadesException(I18n.getResource(ConstantesXADES.LIBRERIAXADES_FIRMAXML_ERROR_51));
158 }
159 idSignatureValue = listElements.get(0).getAttribute(ConstantesXADES.ID);
160
161 if (idSignatureValue == null) {
162
163 logger.info(I18n.getResource(ConstantesXADES.LIBRERIAXADES_FIRMAXML_ERROR_33));
164 throw new AddXadesException(I18n.getResource(ConstantesXADES.LIBRERIAXADES_FIRMAXML_ERROR_51));
165 }
166 }
167
168
169 ArrayList<Element> listElements = UtilidadTratarNodo.obtenerNodos(padreNodoFirmar, 2, ConstantesXADES.QUALIFYING_PROPERTIES);
170 if (listElements.size() != 1) {
171
172 logger.info(I18n.getResource(ConstantesXADES.LIBRERIAXADES_FIRMAXML_ERROR_33));
173 throw new AddXadesException(I18n.getResource(ConstantesXADES.LIBRERIAXADES_FIRMAXML_ERROR_51));
174 }
175 String esquemaOrigen = listElements.get(0).getNamespaceURI();
176 NodeList nodosUnsigSigProp = (padreNodoFirmar).getElementsByTagNameNS(esquemaOrigen,
177 ConstantesXADES.UNSIGNED_SIGNATURE_PROPERTIES);
178
179 Element nodoRaiz = null;
180 if (nodosUnsigSigProp != null && nodosUnsigSigProp.getLength() != 0)
181 nodoRaiz = (Element)nodosUnsigSigProp.item(0);
182 else {
183 NodeList nodosQualifying = (padreNodoFirmar).getElementsByTagNameNS(esquemaOrigen, ConstantesXADES.QUALIFYING_PROPERTIES);
184
185 if (nodosQualifying != null && nodosQualifying.getLength() != 0) {
186 Element nodoQualifying = (Element)nodosQualifying.item(0);
187 Element unsignedProperties = null;
188 if (nodoQualifying.getPrefix() != null) {
189 unsignedProperties =
190 doc.createElementNS(esquemaOrigen, nodoQualifying.getPrefix() +
191 ConstantesXADES.DOS_PUNTOS + ConstantesXADES.UNSIGNED_PROPERTIES);
192 nodoRaiz = doc.createElementNS(esquemaOrigen, nodoQualifying.getPrefix() +
193 ConstantesXADES.DOS_PUNTOS + ConstantesXADES.UNSIGNED_SIGNATURE_PROPERTIES);
194 } else {
195 unsignedProperties =
196 doc.createElementNS(esquemaOrigen, ConstantesXADES.UNSIGNED_PROPERTIES);
197 nodoRaiz = doc.createElementNS(esquemaOrigen, ConstantesXADES.UNSIGNED_SIGNATURE_PROPERTIES);
198 }
199
200 unsignedProperties.appendChild(nodoRaiz);
201 nodosQualifying.item(0).appendChild(unsignedProperties);
202 } else
203 throw new AddXadesException(I18n.getResource(ConstantesXADES.LIBRERIAXADES_FIRMAXML_ERROR_52));
204 }
205
206
207 Element counterSignature = null;
208 if (nodoRaiz.getPrefix() != null) {
209 counterSignature = doc.createElementNS(esquemaOrigen, nodoRaiz.getPrefix() +
210 ConstantesXADES.DOS_PUNTOS + ConstantesXADES.COUNTER_SIGNATURE);
211 } else {
212 counterSignature = doc.createElementNS(esquemaOrigen, ConstantesXADES.COUNTER_SIGNATURE);
213 }
214 nodoRaiz.appendChild(counterSignature);
215
216
217
218 Attr counterSignatureAttrib = doc.createAttributeNS(null, ConstantesXADES.ID);
219 String counterSignatureId = UtilidadTratarNodo.newID(doc, ConstantesXADES.COUNTER_SIGNATURE + ConstantesXADES.GUION);
220 counterSignatureAttrib.setValue(counterSignatureId);
221 counterSignature.getAttributes().setNamedItem(counterSignatureAttrib);
222
223
224 xml.setDocument(doc);
225
226
227 AbstractObjectToSign obj = null;
228 if (XAdESSignature.DEFAULT_XADES_SCHEMA_URI.equals(xadesSchema)) {
229 obj = new SignObjectToSign(idSignatureValue);
230 } else {
231 obj = new InternObjectToSign(idSignatureValue);
232 }
233 xml.addObject(new ObjectToSign(obj, null, null, null, null));
234
235
236
237 xml.setParentSignNode(counterSignatureId);
238 FirmaXML firma = new FirmaXML();
239 if (urlTSA != null) {
240 firma.setTSA(urlTSA.toString());
241 }
242 Object[] res = firma.signFile(certificadoFirma, xml, pk, XAdESUtil.getXAdESDigitalSignatureAlgorithm(digitalSignatureAlgorithm), null);
243
244
245 doc = (Document) res[0];
246
247
248 counterSignature = UtilidadTratarNodo.getElementById(doc, counterSignatureId);
249 counterSignature.removeAttribute(ConstantesXADES.ID);
250
251 return doc;
252 } catch (Exception e) {
253 throw new CounterSignatureException (e);
254 }
255 }
256
257
258
259
260 private static Node buscarNodoAFirmar(Document doc, X509Certificate certificadoContraFirma) {
261
262 XPathFactory factory = XPathFactory.newInstance();
263 XPath xpath = factory.newXPath();
264 NodeList certificateNodes;
265 try {
266 XPathExpression expr = xpath.compile("//*[local-name()='Signature']/*[local-name()='KeyInfo']/*[local-name()='X509Data']/*[local-name()='X509Certificate']");
267 certificateNodes = (NodeList) expr.evaluate (doc, XPathConstants.NODESET);
268 } catch (Exception e) {
269 logger.info ("[ContraFirmaXML.buscarNodoAFirmar]::Error inesperado", e);
270 return null;
271 }
272
273 if (certificateNodes == null || certificateNodes.getLength() == 0) {
274 logger.info("[ContraFirmaXML.buscarNodoAFirmar]::Falta el elemento 'X509Certificate' de la firma, con lo que no es posible obtener la cadena de confianza de un certificado que no existe");
275 return null;
276 }
277
278
279 for (int i = 0; i < certificateNodes.getLength(); i++) {
280 try {
281 X509Certificate x509Cert = Util.getCertificate(Util.decodeBase64(certificateNodes.item(i).getTextContent()));
282 if (x509Cert.equals (certificadoContraFirma)) {
283 return certificateNodes.item(i).getParentNode().getParentNode().getParentNode();
284 }
285 } catch (Exception e) {
286 logger.info ("[ContraFirmaXML.buscarNodoAFirmar]::Error inesperado", e);
287 }
288 }
289
290 return null;
291 }
292
293
294 }