1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.wss4j.dom.message;
21
22 import java.security.InvalidAlgorithmParameterException;
23 import java.security.NoSuchAlgorithmException;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.List;
27
28 import javax.security.auth.callback.Callback;
29 import javax.xml.crypto.XMLStructure;
30 import javax.xml.crypto.dom.DOMStructure;
31 import javax.xml.crypto.dsig.DigestMethod;
32 import javax.xml.crypto.dsig.Transform;
33 import javax.xml.crypto.dsig.XMLSignatureFactory;
34 import javax.xml.crypto.dsig.spec.ExcC14NParameterSpec;
35 import javax.xml.crypto.dsig.spec.TransformParameterSpec;
36
37
38 import org.apache.wss4j.common.WSEncryptionPart;
39 import org.apache.wss4j.common.ext.Attachment;
40 import org.apache.wss4j.common.ext.AttachmentRequestCallback;
41 import org.apache.wss4j.common.ext.WSSecurityException;
42 import org.apache.wss4j.common.util.AttachmentUtils;
43 import org.apache.wss4j.common.util.XMLUtils;
44 import org.apache.wss4j.dom.WSConstants;
45 import org.apache.wss4j.dom.WSDocInfo;
46 import org.apache.wss4j.dom.callback.DOMCallbackLookup;
47 import org.apache.wss4j.dom.transform.AttachmentTransformParameterSpec;
48 import org.apache.wss4j.dom.transform.STRTransform;
49 import org.apache.wss4j.dom.util.SignatureUtils;
50 import org.apache.wss4j.dom.util.WSSecurityUtil;
51 import org.w3c.dom.Document;
52 import org.w3c.dom.Element;
53
54
55
56
57
58 public class WSSecSignatureBase extends WSSecBase {
59
60 private static final org.slf4j.Logger LOG =
61 org.slf4j.LoggerFactory.getLogger(WSSecSignatureBase.class);
62
63 private List<Element> clonedElements = new ArrayList<>();
64
65 public WSSecSignatureBase(WSSecHeader securityHeader) {
66 super(securityHeader);
67 }
68
69 public WSSecSignatureBase(Document doc) {
70 super(doc);
71 }
72
73
74
75
76
77
78
79
80
81
82
83
84 public List<javax.xml.crypto.dsig.Reference> addReferencesToSign(
85 Document doc,
86 List<WSEncryptionPart> references,
87 WSDocInfo wsDocInfo,
88 XMLSignatureFactory signatureFactory,
89 boolean addInclusivePrefixes,
90 String digestAlgo
91 ) throws WSSecurityException {
92 DigestMethod digestMethod;
93 try {
94 digestMethod = signatureFactory.newDigestMethod(digestAlgo, null);
95 } catch (Exception ex) {
96 LOG.error("", ex);
97 throw new WSSecurityException(
98 WSSecurityException.ErrorCode.FAILED_SIGNATURE, ex, "noXMLSig"
99 );
100 }
101
102
103
104 List<javax.xml.crypto.dsig.Reference> attachmentReferenceList = null;
105 List<javax.xml.crypto.dsig.Reference> referenceList = new ArrayList<>();
106
107 for (WSEncryptionPart encPart : references) {
108 String idToSign = encPart.getId();
109 String elemName = encPart.getName();
110 Element element = encPart.getElement();
111
112
113
114
115
116 try {
117 if ("cid:Attachments".equals(idToSign) && attachmentReferenceList == null) {
118 attachmentReferenceList =
119 addAttachmentReferences(encPart, digestMethod, signatureFactory);
120 continue;
121 }
122 if (idToSign != null) {
123 Transform transform = null;
124 if ("STRTransform".equals(elemName)) {
125 Element ctx = createSTRParameter(doc);
126
127 XMLStructure structure = new DOMStructure(ctx);
128 transform =
129 signatureFactory.newTransform(
130 STRTransform.TRANSFORM_URI,
131 structure
132 );
133 } else {
134 TransformParameterSpec transformSpec = null;
135 if (element == null) {
136 if (callbackLookup == null) {
137 callbackLookup = new DOMCallbackLookup(doc);
138 }
139 element = callbackLookup.getElement(idToSign, null, false);
140 }
141 if (addInclusivePrefixes && element != null) {
142 List<String> prefixes = getInclusivePrefixes(element);
143 if (!prefixes.isEmpty()) {
144 transformSpec = new ExcC14NParameterSpec(prefixes);
145 }
146 }
147 transform =
148 signatureFactory.newTransform(
149 WSConstants.C14N_EXCL_OMIT_COMMENTS,
150 transformSpec
151 );
152 }
153 if (element != null) {
154 cloneElement(element);
155
156 wsDocInfo.addTokenElement(element, false);
157 } else if (!encPart.isRequired()) {
158 continue;
159 }
160 javax.xml.crypto.dsig.Reference reference =
161 signatureFactory.newReference(
162 "#" + idToSign,
163 digestMethod,
164 Collections.singletonList(transform),
165 null,
166 null
167 );
168 referenceList.add(reference);
169 } else {
170 String nmSpace = encPart.getNamespace();
171 List<Element> elementsToSign = null;
172 if (element != null) {
173 elementsToSign = Collections.singletonList(element);
174 } else {
175 if (callbackLookup == null) {
176 callbackLookup = new DOMCallbackLookup(doc);
177 }
178 elementsToSign = WSSecurityUtil.findElements(encPart, callbackLookup);
179 }
180 if (elementsToSign == null || elementsToSign.isEmpty()) {
181 if (!encPart.isRequired()) {
182 continue;
183 }
184 throw new WSSecurityException(
185 WSSecurityException.ErrorCode.FAILURE,
186 "noEncElement",
187 new Object[] {nmSpace + ", " + elemName});
188 }
189 for (Element elementToSign : elementsToSign) {
190 String wsuId = setWsuId(elementToSign);
191
192 cloneElement(elementToSign);
193
194 TransformParameterSpec transformSpec = null;
195 if (addInclusivePrefixes) {
196 List<String> prefixes = getInclusivePrefixes(elementToSign);
197 if (!prefixes.isEmpty()) {
198 transformSpec = new ExcC14NParameterSpec(prefixes);
199 }
200 }
201 Transform transform =
202 signatureFactory.newTransform(
203 WSConstants.C14N_EXCL_OMIT_COMMENTS,
204 transformSpec
205 );
206 javax.xml.crypto.dsig.Reference reference =
207 signatureFactory.newReference(
208 "#" + wsuId,
209 digestMethod,
210 Collections.singletonList(transform),
211 null,
212 null
213 );
214 referenceList.add(reference);
215 wsDocInfo.addTokenElement(elementToSign, false);
216 }
217 }
218 } catch (Exception ex) {
219 LOG.error("", ex);
220 throw new WSSecurityException(
221 WSSecurityException.ErrorCode.FAILED_SIGNATURE, ex, "noXMLSig"
222 );
223 }
224 }
225
226
227 if (attachmentReferenceList != null) {
228 referenceList.addAll(attachmentReferenceList);
229 }
230 return referenceList;
231 }
232
233 private void cloneElement(Element element) throws WSSecurityException {
234 if (expandXopInclude) {
235
236 List<Element> includeElements =
237 XMLUtils.findElements(element.getFirstChild(), "Include", WSConstants.XOP_NS);
238 if (includeElements != null && !includeElements.isEmpty()) {
239
240
241
242
243 clonedElements.add(element);
244 Document doc = this.getSecurityHeader().getSecurityHeaderDoc();
245 element.getParentNode().appendChild(WSSecurityUtil.cloneElement(doc, element));
246 WSSecurityUtil.inlineAttachments(includeElements, attachmentCallbackHandler, false);
247 }
248 }
249 }
250
251 private List<javax.xml.crypto.dsig.Reference> addAttachmentReferences(
252 WSEncryptionPart encPart,
253 DigestMethod digestMethod,
254 XMLSignatureFactory signatureFactory
255 ) throws WSSecurityException {
256
257 if (attachmentCallbackHandler == null) {
258 throw new WSSecurityException(
259 WSSecurityException.ErrorCode.FAILURE,
260 "empty", new Object[] {"no attachment callbackhandler supplied"}
261 );
262 }
263
264 AttachmentRequestCallback attachmentRequestCallback = new AttachmentRequestCallback();
265
266
267 String id = AttachmentUtils.getAttachmentId(encPart.getId());
268 attachmentRequestCallback.setAttachmentId(id);
269 try {
270 attachmentCallbackHandler.handle(new Callback[]{attachmentRequestCallback});
271 } catch (Exception e) {
272 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e);
273 }
274
275 List<javax.xml.crypto.dsig.Reference> attachmentReferenceList = new ArrayList<>();
276 if (attachmentRequestCallback.getAttachments() != null) {
277 for (Attachment attachment : attachmentRequestCallback.getAttachments()) {
278 try {
279 List<Transform> transforms = new ArrayList<>();
280
281 AttachmentTransformParameterSpec attachmentTransformParameterSpec =
282 new AttachmentTransformParameterSpec(
283 attachmentCallbackHandler, attachment
284 );
285
286 String attachmentSignatureTransform = WSConstants.SWA_ATTACHMENT_CONTENT_SIG_TRANS;
287 if ("Element".equals(encPart.getEncModifier())) {
288 attachmentSignatureTransform = WSConstants.SWA_ATTACHMENT_COMPLETE_SIG_TRANS;
289 }
290
291 transforms.add(
292 signatureFactory.newTransform(
293 attachmentSignatureTransform, attachmentTransformParameterSpec)
294 );
295
296 javax.xml.crypto.dsig.Reference reference =
297 signatureFactory.newReference(
298 "cid:" + attachment.getId(), digestMethod, transforms, null, null
299 );
300
301 attachmentReferenceList.add(reference);
302 } catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException e) {
303 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e);
304 }
305 }
306 }
307
308 return attachmentReferenceList;
309 }
310
311
312
313
314 public List<String> getInclusivePrefixes(Element target) {
315 return getInclusivePrefixes(target, true);
316 }
317
318
319
320
321
322 public List<String> getInclusivePrefixes(Element target, boolean excludeVisible) {
323 return SignatureUtils.getInclusivePrefixes(target, excludeVisible);
324 }
325
326
327
328
329 public Element createSTRParameter(Document doc) {
330 Element transformParam =
331 doc.createElementNS(
332 WSConstants.WSSE_NS,
333 WSConstants.WSSE_PREFIX + ":TransformationParameters"
334 );
335
336 Element canonElem =
337 doc.createElementNS(
338 WSConstants.SIG_NS,
339 WSConstants.SIG_PREFIX + ":CanonicalizationMethod"
340 );
341
342 canonElem.setAttributeNS(null, "Algorithm", WSConstants.C14N_EXCL_OMIT_COMMENTS);
343 transformParam.appendChild(canonElem);
344 return transformParam;
345 }
346
347 protected void cleanup() {
348 if (!clonedElements.isEmpty()) {
349 for (Element clonedElement : clonedElements) {
350 clonedElement.getParentNode().removeChild(clonedElement);
351 }
352 clonedElements.clear();
353 }
354 }
355
356 }