View Javadoc
1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.wss4j.dom.message;
21  
22  import javax.crypto.KeyGenerator;
23  import javax.crypto.SecretKey;
24  
25  import org.apache.wss4j.common.crypto.AlgorithmSuite;
26  import org.apache.wss4j.common.crypto.Crypto;
27  import org.apache.wss4j.common.crypto.CryptoFactory;
28  import org.apache.wss4j.common.ext.WSSecurityException;
29  import org.apache.wss4j.common.util.KeyUtils;
30  import org.apache.wss4j.common.util.SOAPUtil;
31  import org.apache.wss4j.common.util.XMLUtils;
32  import org.apache.wss4j.dom.WSConstants;
33  import org.apache.wss4j.dom.common.KeystoreCallbackHandler;
34  import org.apache.wss4j.dom.common.SecretKeyCallbackHandler;
35  
36  import org.apache.wss4j.dom.engine.WSSConfig;
37  import org.apache.wss4j.dom.engine.WSSecurityEngine;
38  import org.apache.wss4j.dom.handler.RequestData;
39  import org.apache.wss4j.dom.handler.WSHandlerResult;
40  import org.apache.wss4j.dom.util.WSSecurityUtil;
41  
42  import org.junit.jupiter.api.Test;
43  import org.w3c.dom.Document;
44  import org.w3c.dom.Element;
45  
46  import static org.junit.jupiter.api.Assertions.assertTrue;
47  import static org.junit.jupiter.api.Assertions.fail;
48  
49  /**
50   * A set of test-cases for encrypting and decrypting SOAP requests when specifying an
51   * AlgorithmSuite policy.
52   */
53  public class EncryptionAlgorithmSuiteTest {
54      private static final org.slf4j.Logger LOG =
55          org.slf4j.LoggerFactory.getLogger(EncryptionAlgorithmSuiteTest.class);
56  
57      private Crypto crypto;
58  
59      public EncryptionAlgorithmSuiteTest() throws Exception {
60          WSSConfig.init();
61          crypto = CryptoFactory.getInstance("wss40.properties");
62      }
63  
64      @Test
65      public void testEncryption() throws Exception {
66          Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
67          WSSecHeader secHeader = new WSSecHeader(doc);
68          secHeader.insertSecurityHeader();
69  
70          WSSecEncrypt builder = new WSSecEncrypt(secHeader);
71          builder.setUserInfo("wss40");
72          builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
73          builder.setSymmetricEncAlgorithm(WSConstants.TRIPLE_DES);
74  
75          KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.TRIPLE_DES);
76          SecretKey symmetricKey = keyGen.generateKey();
77          Document encryptedDoc = builder.build(crypto, symmetricKey);
78  
79          if (LOG.isDebugEnabled()) {
80              String outputString =
81                  XMLUtils.prettyDocumentToString(encryptedDoc);
82              LOG.debug(outputString);
83          }
84  
85          Element securityHeader = WSSecurityUtil.getSecurityHeader(encryptedDoc, null);
86          AlgorithmSuite algorithmSuite = createAlgorithmSuite();
87  
88          verify(securityHeader, algorithmSuite, crypto);
89  
90          algorithmSuite.setMinimumAsymmetricKeyLength(1024);
91  
92          try {
93              verify(securityHeader, algorithmSuite, crypto);
94              fail("Expected failure as 512-bit keys are not allowed");
95          } catch (WSSecurityException ex) {
96              assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
97          }
98      }
99  
100     @Test
101     public void testEncryptionKeyTransportRSA15() throws Exception {
102 
103         Crypto wssCrypto = CryptoFactory.getInstance("wss40.properties");
104 
105         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
106         WSSecHeader secHeader = new WSSecHeader(doc);
107         secHeader.insertSecurityHeader();
108 
109         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
110         builder.setUserInfo("wss40");
111         builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
112         builder.setSymmetricEncAlgorithm(WSConstants.TRIPLE_DES);
113         builder.setKeyEncAlgo(WSConstants.KEYTRANSPORT_RSA15);
114 
115         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.TRIPLE_DES);
116         SecretKey symmetricKey = keyGen.generateKey();
117         Document encryptedDoc = builder.build(crypto, symmetricKey);
118 
119         if (LOG.isDebugEnabled()) {
120             String outputString =
121                 XMLUtils.prettyDocumentToString(encryptedDoc);
122             LOG.debug(outputString);
123         }
124 
125         Element securityHeader = WSSecurityUtil.getSecurityHeader(encryptedDoc, null);
126         AlgorithmSuite algorithmSuite = createAlgorithmSuite();
127 
128         try {
129             verify(securityHeader, algorithmSuite, wssCrypto);
130             fail("Expected failure as RSA 15 is not allowed");
131         } catch (WSSecurityException ex) {
132             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
133         }
134 
135         algorithmSuite.addKeyWrapAlgorithm(WSConstants.KEYTRANSPORT_RSA15);
136         verify(securityHeader, algorithmSuite, wssCrypto);
137     }
138 
139     @Test
140     public void testEncryptionKeyTransportRSA15NoAlgorithmSuite() throws Exception {
141 
142         Crypto wssCrypto = CryptoFactory.getInstance("wss40.properties");
143 
144         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
145         WSSecHeader secHeader = new WSSecHeader(doc);
146         secHeader.insertSecurityHeader();
147 
148         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
149         builder.setUserInfo("wss40");
150         builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
151         builder.setSymmetricEncAlgorithm(WSConstants.TRIPLE_DES);
152         builder.setKeyEncAlgo(WSConstants.KEYTRANSPORT_RSA15);
153 
154         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.TRIPLE_DES);
155         SecretKey symmetricKey = keyGen.generateKey();
156         Document encryptedDoc = builder.build(crypto, symmetricKey);
157 
158         if (LOG.isDebugEnabled()) {
159             String outputString =
160                 XMLUtils.prettyDocumentToString(encryptedDoc);
161             LOG.debug(outputString);
162         }
163 
164         Element securityHeader = WSSecurityUtil.getSecurityHeader(encryptedDoc, null);
165 
166         try {
167             verify(securityHeader, null, wssCrypto);
168             fail("Expected failure as RSA 15 is not allowed");
169         } catch (WSSecurityException ex) {
170             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
171         }
172 
173         // Now enable RSA v1.5 processing
174         WSSecurityEngine secEngine = new WSSecurityEngine();
175         RequestData data = new RequestData();
176         data.setDecCrypto(wssCrypto);
177         data.setAllowRSA15KeyTransportAlgorithm(true);
178 
179         data.setCallbackHandler(new KeystoreCallbackHandler());
180 
181         secEngine.processSecurityHeader(securityHeader, data);
182     }
183 
184     @Test
185     public void testEncryptionMethodAES128() throws Exception {
186 
187         Crypto wssCrypto = CryptoFactory.getInstance("wss40.properties");
188 
189         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
190         WSSecHeader secHeader = new WSSecHeader(doc);
191         secHeader.insertSecurityHeader();
192 
193         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
194         builder.setUserInfo("wss40");
195         builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
196         builder.setSymmetricEncAlgorithm(WSConstants.AES_128);
197 
198         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_128);
199         SecretKey symmetricKey = keyGen.generateKey();
200         Document encryptedDoc = builder.build(crypto, symmetricKey);
201 
202         if (LOG.isDebugEnabled()) {
203             String outputString =
204                 XMLUtils.prettyDocumentToString(encryptedDoc);
205             LOG.debug(outputString);
206         }
207 
208         Element securityHeader = WSSecurityUtil.getSecurityHeader(encryptedDoc, null);
209         AlgorithmSuite algorithmSuite = createAlgorithmSuite();
210 
211         try {
212             verify(securityHeader, algorithmSuite, wssCrypto);
213             fail("Expected failure as AES 128 is not allowed");
214         } catch (WSSecurityException ex) {
215             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
216         }
217 
218         algorithmSuite.addEncryptionMethod(WSConstants.AES_128);
219         verify(securityHeader, algorithmSuite, wssCrypto);
220     }
221 
222     @Test
223     public void testSymmetricEncryption() throws Exception {
224 
225         KeyGenerator keyGen = KeyGenerator.getInstance("AES");
226         keyGen.init(128);
227         SecretKey key = keyGen.generateKey();
228         byte[] keyData = key.getEncoded();
229 
230         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
231         WSSecHeader secHeader = new WSSecHeader(doc);
232         secHeader.insertSecurityHeader();
233 
234         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
235         builder.setKeyIdentifierType(WSConstants.ENCRYPTED_KEY_SHA1_IDENTIFIER);
236         builder.setEncryptSymmKey(false);
237 
238         Document encryptedDoc = builder.build(crypto, key);
239 
240         if (LOG.isDebugEnabled()) {
241             String outputString =
242                 XMLUtils.prettyDocumentToString(encryptedDoc);
243             LOG.debug(outputString);
244         }
245 
246         byte[] encodedBytes = KeyUtils.generateDigest(keyData);
247         String identifier = org.apache.xml.security.utils.XMLUtils.encodeToString(encodedBytes);
248         SecretKeyCallbackHandler secretKeyCallbackHandler = new SecretKeyCallbackHandler();
249         secretKeyCallbackHandler.addSecretKey(identifier, keyData);
250 
251         Element securityHeader = WSSecurityUtil.getSecurityHeader(encryptedDoc, null);
252         AlgorithmSuite algorithmSuite = createAlgorithmSuite();
253 
254         WSSecurityEngine secEngine = new WSSecurityEngine();
255         RequestData data = new RequestData();
256         data.setDecCrypto(crypto);
257         data.setCallbackHandler(secretKeyCallbackHandler);
258 
259         data.setAlgorithmSuite(algorithmSuite);
260 
261         algorithmSuite.addEncryptionMethod(WSConstants.AES_128);
262         secEngine.processSecurityHeader(securityHeader, data);
263 
264         algorithmSuite.setMinimumSymmetricKeyLength(256);
265         try {
266             secEngine.processSecurityHeader(securityHeader, data);
267             fail("Expected failure as a 128 bit key is not allowed");
268         } catch (WSSecurityException ex) {
269             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
270         }
271 
272         algorithmSuite.setMinimumSymmetricKeyLength(64);
273         algorithmSuite.setMaximumSymmetricKeyLength(120);
274         try {
275             secEngine.processSecurityHeader(securityHeader, data);
276             fail("Expected failure as a 128 bit key is not allowed");
277         } catch (WSSecurityException ex) {
278             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
279         }
280     }
281 
282 
283     private AlgorithmSuite createAlgorithmSuite() {
284         AlgorithmSuite algorithmSuite = new AlgorithmSuite();
285         algorithmSuite.setMinimumAsymmetricKeyLength(512);
286         algorithmSuite.addKeyWrapAlgorithm(WSConstants.KEYTRANSPORT_RSAOAEP);
287         algorithmSuite.addEncryptionMethod(WSConstants.TRIPLE_DES);
288 
289         return algorithmSuite;
290     }
291 
292     private WSHandlerResult verify(
293         Element securityHeader, AlgorithmSuite algorithmSuite, Crypto decCrypto
294     ) throws Exception {
295         WSSecurityEngine secEngine = new WSSecurityEngine();
296         RequestData data = new RequestData();
297         data.setDecCrypto(decCrypto);
298 
299         data.setAlgorithmSuite(algorithmSuite);
300 
301         data.setCallbackHandler(new KeystoreCallbackHandler());
302 
303         return secEngine.processSecurityHeader(securityHeader, data);
304     }
305 
306 }