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.Collections;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28
29 import javax.crypto.SecretKey;
30 import javax.xml.namespace.QName;
31
32 import org.apache.ws.security.WSConstants;
33 import org.apache.ws.security.WSDataRef;
34 import org.apache.ws.security.WSDerivedKeyTokenPrincipal;
35 import org.apache.ws.security.WSDocInfo;
36 import org.apache.ws.security.WSSConfig;
37 import org.apache.ws.security.WSSecurityEngineResult;
38 import org.apache.ws.security.WSSecurityException;
39 import org.apache.ws.security.components.crypto.AlgorithmSuite;
40 import org.apache.ws.security.components.crypto.AlgorithmSuiteValidator;
41 import org.apache.ws.security.handler.RequestData;
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.Element;
48 import org.w3c.dom.Node;
49
50
51
52
53
54
55 public class EncryptedDataProcessor implements Processor {
56
57 private static org.apache.commons.logging.Log log =
58 org.apache.commons.logging.LogFactory.getLog(EncryptedDataProcessor.class);
59
60 public List<WSSecurityEngineResult> handleToken(
61 Element elem,
62 RequestData request,
63 WSDocInfo wsDocInfo
64 ) throws WSSecurityException {
65 if (log.isDebugEnabled()) {
66 log.debug("Found EncryptedData element");
67 }
68 Element kiElem =
69 WSSecurityUtil.getDirectChildElement(elem, "KeyInfo", WSConstants.SIG_NS);
70
71 if (kiElem == null) {
72 throw new WSSecurityException(
73 WSSecurityException.UNSUPPORTED_ALGORITHM, "noKeyinfo"
74 );
75 }
76
77 String symEncAlgo = X509Util.getEncAlgo(elem);
78
79 if (request.getWssConfig().isWsiBSPCompliant()) {
80 checkBSPCompliance(symEncAlgo);
81 }
82
83
84 Element secRefToken =
85 WSSecurityUtil.getDirectChildElement(
86 kiElem, "SecurityTokenReference", WSConstants.WSSE_NS
87 );
88 Element encryptedKeyElement =
89 WSSecurityUtil.getDirectChildElement(
90 kiElem, WSConstants.ENC_KEY_LN, WSConstants.ENC_NS
91 );
92
93 if (elem != null && request.isRequireSignedEncryptedDataElements()) {
94 WSSecurityUtil.verifySignedElement(elem, elem.getOwnerDocument(), wsDocInfo.getSecurityHeader());
95 }
96
97 SecretKey key = null;
98 List<WSSecurityEngineResult> encrKeyResults = null;
99 Principal principal = null;
100 if (secRefToken != null) {
101 STRParser strParser = new SecurityTokenRefSTRParser();
102 Map<String, Object> parameters = new HashMap<String, Object>();
103 parameters.put(SecurityTokenRefSTRParser.SIGNATURE_METHOD, symEncAlgo);
104 strParser.parseSecurityTokenReference(
105 secRefToken, request,
106 wsDocInfo, parameters
107 );
108 byte[] secretKey = strParser.getSecretKey();
109 principal = strParser.getPrincipal();
110 key = WSSecurityUtil.prepareSecretKey(symEncAlgo, secretKey);
111 } else if (encryptedKeyElement != null) {
112 EncryptedKeyProcessor encrKeyProc = new EncryptedKeyProcessor();
113 encrKeyResults = encrKeyProc.handleToken(encryptedKeyElement, request, wsDocInfo);
114 byte[] symmKey =
115 (byte[])encrKeyResults.get(0).get(WSSecurityEngineResult.TAG_SECRET);
116 key = WSSecurityUtil.prepareSecretKey(symEncAlgo, symmKey);
117 } else {
118 throw new WSSecurityException(
119 WSSecurityException.UNSUPPORTED_ALGORITHM, "noEncKey"
120 );
121 }
122
123
124 AlgorithmSuite algorithmSuite = request.getAlgorithmSuite();
125 if (algorithmSuite != null) {
126 AlgorithmSuiteValidator algorithmSuiteValidator = new
127 AlgorithmSuiteValidator(algorithmSuite);
128
129 if (principal instanceof WSDerivedKeyTokenPrincipal) {
130 algorithmSuiteValidator.checkDerivedKeyAlgorithm(
131 ((WSDerivedKeyTokenPrincipal)principal).getAlgorithm()
132 );
133 algorithmSuiteValidator.checkEncryptionDerivedKeyLength(
134 ((WSDerivedKeyTokenPrincipal)principal).getLength()
135 );
136 }
137 algorithmSuiteValidator.checkSymmetricKeyLength(key.getEncoded().length);
138 algorithmSuiteValidator.checkSymmetricEncryptionAlgorithm(symEncAlgo);
139 }
140
141
142 XMLCipher xmlCipher = null;
143 try {
144 xmlCipher = XMLCipher.getInstance(symEncAlgo);
145 xmlCipher.setSecureValidation(true);
146 xmlCipher.init(XMLCipher.DECRYPT_MODE, key);
147 } catch (XMLEncryptionException ex) {
148 throw new WSSecurityException(
149 WSSecurityException.UNSUPPORTED_ALGORITHM, null, null, ex
150 );
151 }
152 Node previousSibling = elem.getPreviousSibling();
153 Node parent = elem.getParentNode();
154 try {
155 xmlCipher.doFinal(elem.getOwnerDocument(), elem, false);
156 } catch (Exception e) {
157 throw new WSSecurityException(
158 WSSecurityException.FAILED_CHECK, null, null, e
159 );
160 }
161
162 WSDataRef dataRef = new WSDataRef();
163 dataRef.setWsuId(elem.getAttributeNS(null, "Id"));
164 dataRef.setAlgorithm(symEncAlgo);
165 dataRef.setContent(false);
166
167 Node decryptedNode;
168 if (previousSibling == null) {
169 decryptedNode = parent.getFirstChild();
170 } else {
171 decryptedNode = previousSibling.getNextSibling();
172 }
173 if (decryptedNode != null && Node.ELEMENT_NODE == decryptedNode.getNodeType()) {
174 dataRef.setProtectedElement((Element)decryptedNode);
175 }
176 dataRef.setXpath(ReferenceListProcessor.getXPath(decryptedNode));
177
178 WSSecurityEngineResult result =
179 new WSSecurityEngineResult(WSConstants.ENCR, Collections.singletonList(dataRef));
180 result.put(WSSecurityEngineResult.TAG_ID, elem.getAttributeNS(null, "Id"));
181 wsDocInfo.addResult(result);
182 wsDocInfo.addTokenElement(elem);
183
184 WSSConfig wssConfig = request.getWssConfig();
185 if (wssConfig != null) {
186
187 Element decryptedElem;
188 if (previousSibling == null) {
189 decryptedElem = (Element)parent.getFirstChild();
190 } else {
191 decryptedElem = (Element)previousSibling.getNextSibling();
192 }
193 QName el = new QName(decryptedElem.getNamespaceURI(), decryptedElem.getLocalName());
194 Processor proc = request.getWssConfig().getProcessor(el);
195 if (proc != null) {
196 if (log.isDebugEnabled()) {
197 log.debug("Processing decrypted element with: " + proc.getClass().getName());
198 }
199 List<WSSecurityEngineResult> results =
200 proc.handleToken(decryptedElem, request, wsDocInfo);
201 List<WSSecurityEngineResult> completeResults =
202 new ArrayList<WSSecurityEngineResult>();
203 if (encrKeyResults != null) {
204 completeResults.addAll(encrKeyResults);
205 }
206 completeResults.add(result);
207 completeResults.addAll(0, results);
208 return completeResults;
209 }
210 }
211 encrKeyResults.add(result);
212 return encrKeyResults;
213 }
214
215
216
217
218
219
220 private static void checkBSPCompliance(
221 String encAlgo
222 ) throws WSSecurityException {
223
224 if (encAlgo == null) {
225 throw new WSSecurityException(
226 WSSecurityException.UNSUPPORTED_ALGORITHM, "noEncAlgo"
227 );
228 }
229
230 if (!WSConstants.TRIPLE_DES.equals(encAlgo)
231 && !WSConstants.AES_128.equals(encAlgo)
232 && !WSConstants.AES_128_GCM.equals(encAlgo)
233 && !WSConstants.AES_256.equals(encAlgo)
234 && !WSConstants.AES_256_GCM.equals(encAlgo)) {
235 throw new WSSecurityException(
236 WSSecurityException.INVALID_SECURITY, "badEncAlgo", new Object[]{encAlgo}
237 );
238 }
239 }
240
241 }