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 org.apache.wss4j.common.util.SOAPUtil;
23  import org.apache.wss4j.dom.WSConstants;
24  import org.apache.wss4j.dom.common.KeystoreCallbackHandler;
25  
26  import org.apache.wss4j.dom.engine.WSSConfig;
27  import org.apache.wss4j.dom.engine.WSSecurityEngine;
28  import org.apache.wss4j.dom.engine.WSSecurityEngineResult;
29  import org.apache.wss4j.dom.handler.WSHandlerResult;
30  
31  import org.junit.jupiter.api.Test;
32  import org.apache.wss4j.common.crypto.Crypto;
33  import org.apache.wss4j.common.crypto.CryptoFactory;
34  import org.apache.wss4j.common.crypto.CryptoType;
35  import org.apache.wss4j.common.token.SecurityTokenReference;
36  import org.apache.wss4j.common.util.KeyUtils;
37  import org.apache.wss4j.common.util.XMLUtils;
38  import org.w3c.dom.Document;
39  
40  import java.security.cert.X509Certificate;
41  
42  import javax.crypto.KeyGenerator;
43  import javax.crypto.SecretKey;
44  import javax.security.auth.callback.CallbackHandler;
45  
46  import static org.junit.jupiter.api.Assertions.assertFalse;
47  import static org.junit.jupiter.api.Assertions.assertNotNull;
48  import static org.junit.jupiter.api.Assertions.assertTrue;
49  
50  /**
51   * A set of tests for using a derived key for encryption/signature.
52   */
53  public class DerivedKeyTest {
54      private static final org.slf4j.Logger LOG =
55          org.slf4j.LoggerFactory.getLogger(DerivedKeyTest.class);
56      private WSSecurityEngine secEngine = new WSSecurityEngine();
57      private CallbackHandler callbackHandler = new KeystoreCallbackHandler();
58      private Crypto crypto;
59  
60      public DerivedKeyTest() throws Exception {
61          crypto = CryptoFactory.getInstance("wss40.properties");
62          WSSConfig.init();
63      }
64  
65      /**
66       * Test encryption using a DerivedKeyToken using TRIPLEDES
67       * @throws Exception Thrown when there is any problem in signing or
68       * verification
69       */
70      @Test
71      public void testEncryptionDecryptionTRIPLEDES() throws Exception {
72          Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
73          WSSecHeader secHeader = new WSSecHeader(doc);
74          secHeader.insertSecurityHeader();
75  
76          //EncryptedKey
77          WSSecEncryptedKey encrKeyBuilder = new WSSecEncryptedKey(secHeader);
78          encrKeyBuilder.setUserInfo("wss40");
79          encrKeyBuilder.setKeyIdentifierType(WSConstants.THUMBPRINT_IDENTIFIER);
80  
81          KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.TRIPLE_DES);
82          SecretKey symmetricKey = keyGen.generateKey();
83          encrKeyBuilder.prepare(crypto, symmetricKey);
84  
85          //Key information from the EncryptedKey
86          byte[] ek = symmetricKey.getEncoded();
87          String tokenIdentifier = encrKeyBuilder.getId();
88  
89          //Derived key encryption
90          WSSecDKEncrypt encrBuilder = new WSSecDKEncrypt(secHeader);
91          encrBuilder.setSymmetricEncAlgorithm(WSConstants.TRIPLE_DES);
92          encrBuilder.setTokenIdentifier(tokenIdentifier);
93          Document encryptedDoc = encrBuilder.build(ek);
94  
95          encrKeyBuilder.prependToHeader();
96          encrKeyBuilder.prependBSTElementToHeader();
97  
98          String outputString =
99              XMLUtils.prettyDocumentToString(encryptedDoc);
100         if (LOG.isDebugEnabled()) {
101             LOG.debug("Encrypted message: 3DES  + DerivedKeys");
102             LOG.debug(outputString);
103         }
104         assertTrue(outputString.contains(WSConstants.TRIPLE_DES));
105         verify(doc);
106     }
107 
108     /**
109      * Test encryption using a DerivedKeyToken using AES128
110      * @throws Exception Thrown when there is any problem in signing or verification
111      */
112     @Test
113     public void testEncryptionDecryptionAES128() throws Exception {
114         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
115         WSSecHeader secHeader = new WSSecHeader(doc);
116         secHeader.insertSecurityHeader();
117 
118         //EncryptedKey
119         WSSecEncryptedKey encrKeyBuilder = new WSSecEncryptedKey(secHeader);
120         encrKeyBuilder.setUserInfo("wss40");
121         encrKeyBuilder.setKeyIdentifierType(WSConstants.THUMBPRINT_IDENTIFIER);
122 
123         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_128);
124         SecretKey symmetricKey = keyGen.generateKey();
125         encrKeyBuilder.prepare(crypto, symmetricKey);
126 
127         //Key information from the EncryptedKey
128         byte[] ek = symmetricKey.getEncoded();
129         String tokenIdentifier = encrKeyBuilder.getId();
130 
131         //Derived key encryption
132         WSSecDKEncrypt encrBuilder = new WSSecDKEncrypt(secHeader);
133         encrBuilder.setSymmetricEncAlgorithm(WSConstants.AES_128);
134         encrBuilder.setTokenIdentifier(tokenIdentifier);
135         Document encryptedDoc = encrBuilder.build(ek);
136 
137         encrKeyBuilder.prependToHeader();
138         encrKeyBuilder.prependBSTElementToHeader();
139 
140         String outputString =
141             XMLUtils.prettyDocumentToString(encryptedDoc);
142         if (LOG.isDebugEnabled()) {
143             LOG.debug("Encrypted message: AES  + DerivedKeys");
144             LOG.debug(outputString);
145         }
146         assertTrue(outputString.contains(WSConstants.AES_128));
147         verify(doc);
148     }
149 
150     @Test
151     public void testEncryptionDecryptionAES256() throws Exception {
152         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
153         WSSecHeader secHeader = new WSSecHeader(doc);
154         secHeader.insertSecurityHeader();
155 
156         //EncryptedKey
157         WSSecEncryptedKey encrKeyBuilder = new WSSecEncryptedKey(secHeader);
158         encrKeyBuilder.setUserInfo("wss40");
159         encrKeyBuilder.setKeyIdentifierType(WSConstants.THUMBPRINT_IDENTIFIER);
160 
161         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_256);
162         SecretKey symmetricKey = keyGen.generateKey();
163         encrKeyBuilder.prepare(crypto, symmetricKey);
164 
165         //Key information from the EncryptedKey
166         byte[] ek = symmetricKey.getEncoded();
167         String tokenIdentifier = encrKeyBuilder.getId();
168 
169         //Derived key encryption
170         WSSecDKEncrypt encrBuilder = new WSSecDKEncrypt(secHeader);
171         encrBuilder.setSymmetricEncAlgorithm(WSConstants.AES_256);
172         encrBuilder.setTokenIdentifier(tokenIdentifier);
173         Document encryptedDoc = encrBuilder.build(ek);
174 
175         encrKeyBuilder.prependToHeader();
176         encrKeyBuilder.prependBSTElementToHeader();
177 
178         String outputString =
179             XMLUtils.prettyDocumentToString(encryptedDoc);
180         if (LOG.isDebugEnabled()) {
181             LOG.debug("Encrypted message: AES  + DerivedKeys");
182             LOG.debug(outputString);
183         }
184         assertTrue(outputString.contains(WSConstants.AES_256));
185         verify(doc);
186      }
187 
188     @Test
189     public void testSignature() throws Exception {
190         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
191         WSSecHeader secHeader = new WSSecHeader(doc);
192         secHeader.insertSecurityHeader();
193 
194         //EncryptedKey
195         WSSecEncryptedKey encrKeyBuilder = new WSSecEncryptedKey(secHeader);
196         encrKeyBuilder.setUserInfo("wss40");
197         encrKeyBuilder.setKeyIdentifierType(WSConstants.THUMBPRINT_IDENTIFIER);
198 
199         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_128);
200         SecretKey symmetricKey = keyGen.generateKey();
201         encrKeyBuilder.prepare(crypto, symmetricKey);
202 
203         //Key information from the EncryptedKey
204         byte[] ek = symmetricKey.getEncoded();
205         String tokenIdentifier = encrKeyBuilder.getId();
206 
207         //Derived key encryption
208         WSSecDKSign sigBuilder = new WSSecDKSign(secHeader);
209         sigBuilder.setTokenIdentifier(tokenIdentifier);
210         sigBuilder.setSignatureAlgorithm(WSConstants.HMAC_SHA1);
211         /* Document signedDoc = */ sigBuilder.build(ek);
212 
213         encrKeyBuilder.prependToHeader();
214         encrKeyBuilder.prependBSTElementToHeader();
215 
216         if (LOG.isDebugEnabled()) {
217             LOG.debug("Signed message: 3DES  + DerivedKeys");
218             String outputString =
219                 XMLUtils.prettyDocumentToString(doc);
220             LOG.debug(outputString);
221         }
222         WSHandlerResult results = verify(doc);
223 
224         WSSecurityEngineResult actionResult =
225             results.getActionResults().get(WSConstants.SIGN).get(0);
226         assertNotNull(actionResult);
227         assertFalse(actionResult.isEmpty());
228         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_SECRET));
229     }
230 
231 
232     /**
233      * A test for WSS-211 - "WSS4J does not support ThumbprintSHA1 in DerivedKeyTokens".
234      * Here we're signing the SOAP body, where the signature refers to a DerivedKeyToken
235      * which uses a Thumbprint-SHA1 reference to the encoded certificate (which is in the
236      * keystore)
237      */
238     @Test
239     public void testSignatureThumbprintSHA1() throws Exception {
240         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
241         WSSecHeader secHeader = new WSSecHeader(doc);
242         secHeader.insertSecurityHeader();
243 
244         SecurityTokenReference secToken = new SecurityTokenReference(doc);
245         CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
246         cryptoType.setAlias("wss40");
247         X509Certificate[] certs = crypto.getX509Certificates(cryptoType);
248         secToken.setKeyIdentifierThumb(certs[0]);
249 
250         WSSecDKSign sigBuilder = new WSSecDKSign(secHeader);
251         java.security.Key key = crypto.getPrivateKey("wss40", "security");
252         sigBuilder.setSignatureAlgorithm(WSConstants.HMAC_SHA1);
253         sigBuilder.setStrElem(secToken.getElement());
254         sigBuilder.build(key.getEncoded());
255 
256         sigBuilder.prependDKElementToHeader();
257 
258         if (LOG.isDebugEnabled()) {
259             LOG.debug("Encrypted message: ThumbprintSHA1 + DerivedKeys");
260             String outputString =
261                 XMLUtils.prettyDocumentToString(doc);
262             LOG.debug(outputString);
263         }
264         WSHandlerResult results = verify(doc);
265 
266         WSSecurityEngineResult actionResult =
267             results.getActionResults().get(WSConstants.SIGN).get(0);
268         assertNotNull(actionResult);
269         assertFalse(actionResult.isEmpty());
270         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_SECRET));
271     }
272 
273 
274     /**
275      * Here we're signing the SOAP body, where the signature refers to a DerivedKeyToken
276      * which uses an SKI reference to the encoded certificate (which is in the
277      * keystore)
278      */
279     @Test
280     public void testSignatureSKI() throws Exception {
281         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
282         WSSecHeader secHeader = new WSSecHeader(doc);
283         secHeader.insertSecurityHeader();
284 
285         SecurityTokenReference secToken = new SecurityTokenReference(doc);
286         CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
287         cryptoType.setAlias("wss40");
288         X509Certificate[] certs = crypto.getX509Certificates(cryptoType);
289         secToken.setKeyIdentifierSKI(certs[0], crypto);
290 
291         WSSecDKSign sigBuilder = new WSSecDKSign(secHeader);
292         java.security.Key key = crypto.getPrivateKey("wss40", "security");
293         sigBuilder.setSignatureAlgorithm(WSConstants.HMAC_SHA1);
294         sigBuilder.setStrElem(secToken.getElement());
295         sigBuilder.build(key.getEncoded());
296 
297         sigBuilder.prependDKElementToHeader();
298 
299         if (LOG.isDebugEnabled()) {
300             LOG.debug("Encrypted message: SKI + DerivedKeys");
301             String outputString =
302                 XMLUtils.prettyDocumentToString(doc);
303             LOG.debug(outputString);
304         }
305         WSHandlerResult results = verify(doc);
306 
307         WSSecurityEngineResult actionResult =
308             results.getActionResults().get(WSConstants.SIGN).get(0);
309         assertNotNull(actionResult);
310         assertFalse(actionResult.isEmpty());
311         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_SECRET));
312     }
313 
314     @Test
315     public void testSignatureEncrypt() throws Exception {
316         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
317         WSSecHeader secHeader = new WSSecHeader(doc);
318         secHeader.insertSecurityHeader();
319 
320         //EncryptedKey
321         WSSecEncryptedKey encrKeyBuilder = new WSSecEncryptedKey(secHeader);
322         encrKeyBuilder.setUserInfo("wss40");
323         encrKeyBuilder.setKeyIdentifierType(WSConstants.THUMBPRINT_IDENTIFIER);
324 
325         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_128);
326         SecretKey symmetricKey = keyGen.generateKey();
327         encrKeyBuilder.prepare(crypto, symmetricKey);
328 
329         //Key information from the EncryptedKey
330         byte[] ek = symmetricKey.getEncoded();
331         String tokenIdentifier = encrKeyBuilder.getId();
332 
333         //Derived key encryption
334         WSSecDKSign sigBuilder = new WSSecDKSign(secHeader);
335         sigBuilder.setTokenIdentifier(tokenIdentifier);
336         sigBuilder.setSignatureAlgorithm(WSConstants.HMAC_SHA1);
337         LOG.info("Before HMAC-SHA1 signature");
338         sigBuilder.build(ek);
339 
340         //Derived key signature
341         WSSecDKEncrypt encrBuilder = new WSSecDKEncrypt(secHeader);
342         encrBuilder.setSymmetricEncAlgorithm(WSConstants.AES_128);
343         encrBuilder.setTokenIdentifier(tokenIdentifier);
344         Document signedEncryptedDoc = encrBuilder.build(ek);
345 
346         encrKeyBuilder.prependToHeader();
347         encrKeyBuilder.prependBSTElementToHeader();
348 
349         if (LOG.isDebugEnabled()) {
350             LOG.debug("Encrypted message: 3DES  + DerivedKeys");
351             String outputString =
352                 XMLUtils.prettyDocumentToString(signedEncryptedDoc);
353             LOG.debug(outputString);
354         }
355         verify(signedEncryptedDoc);
356     }
357 
358     @Test
359     public void testEncryptSignature() throws Exception {
360         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
361         WSSecHeader secHeader = new WSSecHeader(doc);
362         secHeader.insertSecurityHeader();
363 
364         //EncryptedKey
365         WSSecEncryptedKey encrKeyBuilder = new WSSecEncryptedKey(secHeader);
366         encrKeyBuilder.setUserInfo("wss40");
367         encrKeyBuilder.setKeyIdentifierType(WSConstants.THUMBPRINT_IDENTIFIER);
368 
369         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_128);
370         SecretKey symmetricKey = keyGen.generateKey();
371         encrKeyBuilder.prepare(crypto, symmetricKey);
372 
373         //Key information from the EncryptedKey
374         byte[] ek = symmetricKey.getEncoded();
375         String tokenIdentifier = encrKeyBuilder.getId();
376 
377         //Derived key encryption
378         WSSecDKEncrypt encrBuilder = new WSSecDKEncrypt(secHeader);
379         encrBuilder.setSymmetricEncAlgorithm(WSConstants.AES_128);
380         encrBuilder.setTokenIdentifier(tokenIdentifier);
381         encrBuilder.build(ek);
382 
383         //Derived key signature
384         WSSecDKSign sigBuilder = new WSSecDKSign(secHeader);
385         sigBuilder.setTokenIdentifier(tokenIdentifier);
386         sigBuilder.setSignatureAlgorithm(WSConstants.HMAC_SHA1);
387         LOG.info("Before HMAC-SHA1 signature");
388         Document encryptedSignedDoc = sigBuilder.build(ek);
389 
390         encrKeyBuilder.prependToHeader();
391         encrKeyBuilder.prependBSTElementToHeader();
392 
393         if (LOG.isDebugEnabled()) {
394             LOG.debug("Encrypted message: 3DES  + DerivedKeys");
395             String outputString =
396                 XMLUtils.prettyDocumentToString(encryptedSignedDoc);
397             LOG.debug(outputString);
398         }
399 
400         verify(encryptedSignedDoc);
401     }
402 
403     /**
404      * Verifies the soap envelope
405      * <p/>
406      *
407      * @param envelope
408      * @throws Exception Thrown when there is a problem in verification
409      */
410     private WSHandlerResult verify(Document doc) throws Exception {
411         WSHandlerResult results =
412             secEngine.processSecurityHeader(doc, null, callbackHandler, crypto);
413         String outputString =
414             XMLUtils.prettyDocumentToString(doc);
415         assertTrue(outputString.indexOf("counter_port_type") > 0 ? true : false);
416 
417         return results;
418     }
419 
420 }