1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.ws.security.processor;
21
22 import java.security.Principal;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27
28 import javax.crypto.SecretKey;
29
30 import org.apache.ws.security.WSConstants;
31 import org.apache.ws.security.WSDataRef;
32 import org.apache.ws.security.WSDerivedKeyTokenPrincipal;
33 import org.apache.ws.security.WSDocInfo;
34 import org.apache.ws.security.WSSecurityEngineResult;
35 import org.apache.ws.security.WSSecurityException;
36 import org.apache.ws.security.components.crypto.AlgorithmSuite;
37 import org.apache.ws.security.components.crypto.AlgorithmSuiteValidator;
38 import org.apache.ws.security.handler.RequestData;
39 import org.apache.ws.security.message.CallbackLookup;
40 import org.apache.ws.security.message.DOMCallbackLookup;
41 import org.apache.ws.security.message.token.SecurityTokenReference;
42 import org.apache.ws.security.str.STRParser;
43 import org.apache.ws.security.str.SecurityTokenRefSTRParser;
44 import org.apache.ws.security.util.WSSecurityUtil;
45 import org.apache.xml.security.encryption.XMLCipher;
46 import org.apache.xml.security.encryption.XMLEncryptionException;
47 import org.w3c.dom.Attr;
48 import org.w3c.dom.Document;
49 import org.w3c.dom.Element;
50 import org.w3c.dom.Node;
51
52 public class ReferenceListProcessor implements Processor {
53 private static org.apache.commons.logging.Log log =
54 org.apache.commons.logging.LogFactory.getLog(ReferenceListProcessor.class);
55
56 public List<WSSecurityEngineResult> handleToken(
57 Element elem,
58 RequestData data,
59 WSDocInfo wsDocInfo
60 ) throws WSSecurityException {
61 if (log.isDebugEnabled()) {
62 log.debug("Found reference list element");
63 }
64 List<WSDataRef> dataRefs = handleReferenceList(elem, data, wsDocInfo);
65 WSSecurityEngineResult result =
66 new WSSecurityEngineResult(WSConstants.ENCR, dataRefs);
67 result.put(WSSecurityEngineResult.TAG_ID, elem.getAttributeNS(null, "Id"));
68 wsDocInfo.addTokenElement(elem);
69 wsDocInfo.addResult(result);
70 return java.util.Collections.singletonList(result);
71 }
72
73
74
75
76
77
78
79
80
81 private List<WSDataRef> handleReferenceList(
82 Element elem,
83 RequestData data,
84 WSDocInfo wsDocInfo
85 ) throws WSSecurityException {
86 List<WSDataRef> dataRefs = new ArrayList<WSDataRef>();
87
88 Element wsseHeaderElement = wsDocInfo.getSecurityHeader();
89 boolean asymBinding = WSSecurityUtil.getDirectChildElement(
90 wsseHeaderElement, WSConstants.ENC_KEY_LN, WSConstants.ENC_NS) != null;
91 for (Node node = elem.getFirstChild();
92 node != null;
93 node = node.getNextSibling()
94 ) {
95 if (Node.ELEMENT_NODE == node.getNodeType()
96 && WSConstants.ENC_NS.equals(node.getNamespaceURI())
97 && "DataReference".equals(node.getLocalName())) {
98 String dataRefURI = ((Element) node).getAttribute("URI");
99 if (dataRefURI.charAt(0) == '#') {
100 dataRefURI = dataRefURI.substring(1);
101 }
102
103 if (wsDocInfo.getResultByTag(WSConstants.ENCR, dataRefURI) == null) {
104 WSDataRef dataRef =
105 decryptDataRefEmbedded(
106 elem.getOwnerDocument(), dataRefURI, data, wsDocInfo, asymBinding);
107 dataRefs.add(dataRef);
108 }
109 }
110 }
111
112 return dataRefs;
113 }
114
115
116
117
118
119 private WSDataRef decryptDataRefEmbedded(
120 Document doc,
121 String dataRefURI,
122 RequestData data,
123 WSDocInfo wsDocInfo,
124 boolean asymBinding
125 ) throws WSSecurityException {
126 if (log.isDebugEnabled()) {
127 log.debug("Found data reference: " + dataRefURI);
128 }
129
130
131
132 Element encryptedDataElement = findEncryptedDataElement(doc, wsDocInfo, dataRefURI);
133
134 if (encryptedDataElement != null && asymBinding && data.isRequireSignedEncryptedDataElements()) {
135 WSSecurityUtil.verifySignedElement(encryptedDataElement, doc, wsDocInfo.getSecurityHeader());
136 }
137
138
139
140 String symEncAlgo = X509Util.getEncAlgo(encryptedDataElement);
141 Element keyInfoElement =
142 (Element)WSSecurityUtil.getDirectChildElement(
143 encryptedDataElement, "KeyInfo", WSConstants.SIG_NS
144 );
145
146 if (keyInfoElement == null) {
147 throw new WSSecurityException(WSSecurityException.INVALID_SECURITY, "noKeyinfo");
148 }
149
150 if (data.getWssConfig().isWsiBSPCompliant()) {
151 checkBSPCompliance(keyInfoElement, symEncAlgo);
152 }
153
154
155
156
157 Element secRefToken =
158 WSSecurityUtil.getDirectChildElement(
159 keyInfoElement, "SecurityTokenReference", WSConstants.WSSE_NS
160 );
161 SecretKey symmetricKey = null;
162 Principal principal = null;
163 if (secRefToken == null) {
164 symmetricKey = X509Util.getSharedKey(keyInfoElement, symEncAlgo, data.getCallbackHandler());
165 } else {
166 STRParser strParser = new SecurityTokenRefSTRParser();
167 Map<String, Object> parameters = new HashMap<String, Object>();
168 parameters.put(SecurityTokenRefSTRParser.SIGNATURE_METHOD, symEncAlgo);
169 strParser.parseSecurityTokenReference(
170 secRefToken, data,
171 wsDocInfo, parameters
172 );
173 byte[] secretKey = strParser.getSecretKey();
174 principal = strParser.getPrincipal();
175 symmetricKey = WSSecurityUtil.prepareSecretKey(symEncAlgo, secretKey);
176 }
177
178
179 AlgorithmSuite algorithmSuite = data.getAlgorithmSuite();
180 if (algorithmSuite != null) {
181 AlgorithmSuiteValidator algorithmSuiteValidator = new
182 AlgorithmSuiteValidator(algorithmSuite);
183
184 if (principal instanceof WSDerivedKeyTokenPrincipal) {
185 algorithmSuiteValidator.checkDerivedKeyAlgorithm(
186 ((WSDerivedKeyTokenPrincipal)principal).getAlgorithm()
187 );
188 algorithmSuiteValidator.checkEncryptionDerivedKeyLength(
189 ((WSDerivedKeyTokenPrincipal)principal).getLength()
190 );
191 }
192
193 algorithmSuiteValidator.checkSymmetricKeyLength(symmetricKey.getEncoded().length);
194 algorithmSuiteValidator.checkSymmetricEncryptionAlgorithm(symEncAlgo);
195 }
196
197 return
198 decryptEncryptedData(
199 doc, dataRefURI, encryptedDataElement, symmetricKey, symEncAlgo
200 );
201 }
202
203
204
205
206
207
208
209 private static void checkBSPCompliance(
210 Element keyInfoElement,
211 String encAlgo
212 ) throws WSSecurityException {
213
214 int result = 0;
215 Node node = keyInfoElement.getFirstChild();
216 Element child = null;
217 while (node != null) {
218 if (Node.ELEMENT_NODE == node.getNodeType()) {
219 result++;
220 child = (Element)node;
221 }
222 node = node.getNextSibling();
223 }
224 if (result != 1) {
225 throw new WSSecurityException(
226 WSSecurityException.INVALID_SECURITY, "invalidDataRef"
227 );
228 }
229
230 if (!WSConstants.WSSE_NS.equals(child.getNamespaceURI()) ||
231 !SecurityTokenReference.SECURITY_TOKEN_REFERENCE.equals(child.getLocalName())) {
232 throw new WSSecurityException(
233 WSSecurityException.INVALID_SECURITY, "noSecTokRef"
234 );
235 }
236
237
238 if (encAlgo == null) {
239 throw new WSSecurityException(
240 WSSecurityException.UNSUPPORTED_ALGORITHM, "noEncAlgo"
241 );
242 }
243
244 if (!WSConstants.TRIPLE_DES.equals(encAlgo)
245 && !WSConstants.AES_128.equals(encAlgo)
246 && !WSConstants.AES_128_GCM.equals(encAlgo)
247 && !WSConstants.AES_256.equals(encAlgo)
248 && !WSConstants.AES_256_GCM.equals(encAlgo)) {
249 throw new WSSecurityException(
250 WSSecurityException.INVALID_SECURITY, "badEncAlgo", new Object[]{encAlgo}
251 );
252 }
253 }
254
255
256
257
258
259
260
261
262
263
264
265
266 public static Element
267 findEncryptedDataElement(
268 Document doc,
269 WSDocInfo wsDocInfo,
270 String dataRefURI
271 ) throws WSSecurityException {
272 CallbackLookup callbackLookup = wsDocInfo.getCallbackLookup();
273 if (callbackLookup == null) {
274 callbackLookup = new DOMCallbackLookup(doc);
275 }
276 Element encryptedDataElement =
277 callbackLookup.getElement(dataRefURI, null, true);
278 if (encryptedDataElement == null) {
279 throw new WSSecurityException(
280 WSSecurityException.INVALID_SECURITY, "dataRef", new Object[] {dataRefURI}
281 );
282 }
283 if (encryptedDataElement.getLocalName().equals(WSConstants.ENCRYPTED_HEADER)
284 && encryptedDataElement.getNamespaceURI().equals(WSConstants.WSSE11_NS)) {
285 Node child = encryptedDataElement.getFirstChild();
286 while (child != null && child.getNodeType() != Node.ELEMENT_NODE) {
287 child = child.getNextSibling();
288 }
289 return (Element)child;
290 }
291 return encryptedDataElement;
292 }
293
294
295
296
297
298
299
300
301
302
303
304 public static WSDataRef
305 decryptEncryptedData(
306 Document doc,
307 String dataRefURI,
308 Element encData,
309 SecretKey symmetricKey,
310 String symEncAlgo
311 ) throws WSSecurityException {
312 XMLCipher xmlCipher = null;
313 try {
314 xmlCipher = XMLCipher.getInstance(symEncAlgo);
315 xmlCipher.setSecureValidation(true);
316 xmlCipher.init(XMLCipher.DECRYPT_MODE, symmetricKey);
317 } catch (XMLEncryptionException ex) {
318 throw new WSSecurityException(
319 WSSecurityException.UNSUPPORTED_ALGORITHM, null, null, ex
320 );
321 }
322
323 WSDataRef dataRef = new WSDataRef();
324 dataRef.setWsuId(dataRefURI);
325 dataRef.setAlgorithm(symEncAlgo);
326 boolean content = X509Util.isContent(encData);
327 dataRef.setContent(content);
328
329 Node parent = encData.getParentNode();
330 Node previousSibling = encData.getPreviousSibling();
331 if (content) {
332 encData = (Element) encData.getParentNode();
333 parent = encData.getParentNode();
334 }
335
336 try {
337 xmlCipher.doFinal(doc, encData, content);
338 } catch (Exception ex) {
339 throw new WSSecurityException(WSSecurityException.FAILED_CHECK, null, null, ex);
340 }
341
342 if (parent.getLocalName().equals(WSConstants.ENCRYPTED_HEADER)
343 && parent.getNamespaceURI().equals(WSConstants.WSSE11_NS)) {
344
345 Node decryptedHeader = parent.getFirstChild();
346 Node soapHeader = parent.getParentNode();
347 soapHeader.replaceChild(decryptedHeader, parent);
348
349 dataRef.setProtectedElement((Element)decryptedHeader);
350 dataRef.setXpath(getXPath(decryptedHeader));
351 } else if (content) {
352 dataRef.setProtectedElement(encData);
353 dataRef.setXpath(getXPath(encData));
354 } else {
355 Node decryptedNode;
356 if (previousSibling == null) {
357 decryptedNode = parent.getFirstChild();
358 } else {
359 decryptedNode = previousSibling.getNextSibling();
360 }
361 if (decryptedNode != null && Node.ELEMENT_NODE == decryptedNode.getNodeType()) {
362 dataRef.setProtectedElement((Element)decryptedNode);
363 }
364 dataRef.setXpath(getXPath(decryptedNode));
365 }
366
367 return dataRef;
368 }
369
370
371 public String getId() {
372 return null;
373 }
374
375
376
377
378
379
380
381
382
383 public static String getXPath(Node decryptedNode) {
384 if (decryptedNode == null) {
385 return null;
386 }
387
388 String result = "";
389 if (Node.ELEMENT_NODE == decryptedNode.getNodeType()) {
390 result = decryptedNode.getNodeName();
391 result = prependFullPath(result, decryptedNode.getParentNode());
392 } else if (Node.ATTRIBUTE_NODE == decryptedNode.getNodeType()) {
393 result = "@" + decryptedNode.getNodeName();
394 result = prependFullPath(result, ((Attr)decryptedNode).getOwnerElement());
395 } else {
396 return null;
397 }
398
399 return result;
400 }
401
402
403
404
405
406
407
408
409
410 private static String prependFullPath(String xpath, Node node) {
411 if (node == null) {
412
413 return null;
414 } else if (Node.ELEMENT_NODE == node.getNodeType()) {
415 xpath = node.getNodeName() + "/" + xpath;
416 return prependFullPath(xpath, node.getParentNode());
417 } else if (Node.DOCUMENT_NODE == node.getNodeType()) {
418 return "/" + xpath;
419 } else {
420 return prependFullPath(xpath, node.getParentNode());
421 }
422 }
423
424 }