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 java.security.cert.X509Certificate;
23  import java.util.ArrayList;
24  import java.util.Collections;
25  
26  import javax.crypto.KeyGenerator;
27  import javax.crypto.SecretKey;
28  import javax.security.auth.callback.CallbackHandler;
29  
30  import org.apache.wss4j.common.WSEncryptionPart;
31  import org.apache.wss4j.common.bsp.BSPRule;
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.ext.WSSecurityException;
36  import org.apache.wss4j.common.util.DOM2Writer;
37  import org.apache.wss4j.common.util.KeyUtils;
38  import org.apache.wss4j.common.util.SOAPUtil;
39  import org.apache.wss4j.common.util.XMLUtils;
40  import org.apache.wss4j.dom.SOAPConstants;
41  import org.apache.wss4j.dom.WSConstants;
42  import org.apache.wss4j.dom.WSDataRef;
43  import org.apache.wss4j.dom.common.CustomHandler;
44  import org.apache.wss4j.dom.common.KeystoreCallbackHandler;
45  import org.apache.wss4j.dom.common.SecretKeyCallbackHandler;
46  
47  import org.apache.wss4j.dom.engine.WSSConfig;
48  import org.apache.wss4j.dom.engine.WSSecurityEngine;
49  import org.apache.wss4j.dom.engine.WSSecurityEngineResult;
50  import org.apache.wss4j.dom.handler.HandlerAction;
51  import org.apache.wss4j.dom.handler.RequestData;
52  import org.apache.wss4j.dom.handler.WSHandlerConstants;
53  import org.apache.wss4j.dom.handler.WSHandlerResult;
54  import org.apache.wss4j.dom.str.STRParser.REFERENCE_TYPE;
55  import org.apache.wss4j.dom.util.WSSecurityUtil;
56  
57  import org.junit.jupiter.api.BeforeEach;
58  import org.junit.jupiter.api.Test;
59  import org.w3c.dom.Document;
60  import org.w3c.dom.Element;
61  
62  import static org.junit.jupiter.api.Assertions.assertEquals;
63  import static org.junit.jupiter.api.Assertions.assertFalse;
64  import static org.junit.jupiter.api.Assertions.assertNotNull;
65  import static org.junit.jupiter.api.Assertions.assertTrue;
66  import static org.junit.jupiter.api.Assertions.fail;
67  
68  /**
69   * A set of test-cases for encrypting and decrypting SOAP requests.
70   */
71  public class EncryptionTest {
72      private static final org.slf4j.Logger LOG =
73          org.slf4j.LoggerFactory.getLogger(EncryptionTest.class);
74      private static final javax.xml.namespace.QName SOAP_BODY =
75          new javax.xml.namespace.QName(
76              WSConstants.URI_SOAP11_ENV,
77              "Body"
78          );
79  
80      private WSSecurityEngine secEngine = new WSSecurityEngine();
81      private CallbackHandler keystoreCallbackHandler = new KeystoreCallbackHandler();
82      private SecretKeyCallbackHandler secretKeyCallbackHandler = new SecretKeyCallbackHandler();
83      private byte[] keyData;
84      private SecretKey key;
85      private Crypto crypto;
86  
87      public EncryptionTest() throws Exception {
88          crypto = CryptoFactory.getInstance("wss40.properties");
89      }
90  
91      /**
92       * Setup method
93       *
94       * @throws Exception Thrown when there is a problem in setup
95       */
96      @BeforeEach
97      public void setUp() throws Exception {
98          KeyGenerator keyGen = KeyGenerator.getInstance("AES");
99          keyGen.init(128);
100         key = keyGen.generateKey();
101         keyData = key.getEncoded();
102         secEngine.setWssConfig(WSSConfig.getNewInstance());
103     }
104 
105     /**
106      * Test that encrypt and decrypt a WS-Security envelope.
107      * This test uses the RSA_15 algorithm to transport (wrap) the symmetric
108      * key.
109      * <p/>
110      *
111      * @throws Exception Thrown when there is any problem in signing or verification
112      */
113     @Test
114     public void testEncryptionDecryptionRSA15() throws Exception {
115         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
116         WSSecHeader secHeader = new WSSecHeader(doc);
117         secHeader.insertSecurityHeader();
118 
119         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
120         builder.setUserInfo("wss40");
121         builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
122         builder.setSymmetricEncAlgorithm(WSConstants.TRIPLE_DES);
123 
124         LOG.info("Before Encryption Triple DES....");
125         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.TRIPLE_DES);
126         SecretKey symmetricKey = keyGen.generateKey();
127         Document encryptedDoc = builder.build(crypto, symmetricKey);
128         LOG.info("After Encryption Triple DES....");
129 
130         String outputString =
131             XMLUtils.prettyDocumentToString(encryptedDoc);
132         if (LOG.isDebugEnabled()) {
133             LOG.debug("Encrypted message, RSA-15 keytransport, 3DES:");
134             LOG.debug(outputString);
135         }
136         assertFalse(outputString.contains("counter_port_type"));
137         verify(encryptedDoc, keystoreCallbackHandler, SOAP_BODY);
138         builder.getParts().clear();
139 
140         /*
141          * second run, same Junit set up, but change encryption method,
142          * key identification, encryption mode (Element now), and data to encrypt.
143          * This tests if several runs of different algorithms on same builder/cipher
144          * setup are ok.
145          */
146         doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
147         secHeader = new WSSecHeader(doc);
148         secHeader.insertSecurityHeader();
149 
150         builder = new WSSecEncrypt(secHeader);
151         builder.setUserInfo("wss40");
152         builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
153         builder.setSymmetricEncAlgorithm(WSConstants.AES_128);
154 
155         WSEncryptionPart encP =
156             new WSEncryptionPart(
157                 "add", "http://ws.apache.org/counter/counter_port_type", "Element"
158             );
159         builder.getParts().add(encP);
160 
161         LOG.info("Before Encryption AES 128/RSA-15....");
162         keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_128);
163         symmetricKey = keyGen.generateKey();
164         encryptedDoc = builder.build(crypto, symmetricKey);
165         LOG.info("After Encryption AES 128/RSA-15....");
166         outputString =
167             XMLUtils.prettyDocumentToString(encryptedDoc);
168         if (LOG.isDebugEnabled()) {
169             LOG.debug("Encrypted message, RSA-15 keytransport, AES 128:");
170             LOG.debug(outputString);
171         }
172         assertFalse(outputString.contains("counter_port_type"));
173         WSHandlerResult results = verify(
174             encryptedDoc,
175             keystoreCallbackHandler,
176             new javax.xml.namespace.QName(
177                 "http://ws.apache.org/counter/counter_port_type",
178                 "add"
179             )
180         );
181 
182         WSSecurityEngineResult actionResult =
183                 results.getActionResults().get(WSConstants.ENCR).get(0);
184         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE));
185         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE));
186         REFERENCE_TYPE referenceType =
187             (REFERENCE_TYPE)actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE);
188         assertTrue(referenceType == REFERENCE_TYPE.ISSUER_SERIAL);
189     }
190 
191     /**
192      * Test that encrypt and decrypt a WS-Security envelope.
193      * This test uses the RSA OAEP algorithm to transport (wrap) the symmetric
194      * key.
195      * <p/>
196      *
197      * @throws Exception Thrown when there is any problem in signing or verification
198      */
199     @Test
200     public void testEncryptionDecryptionOAEP() throws Exception {
201         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
202         WSSecHeader secHeader = new WSSecHeader(doc);
203         secHeader.insertSecurityHeader();
204 
205         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
206         builder.setUserInfo("wss40");
207         builder.setKeyIdentifierType(WSConstants.X509_KEY_IDENTIFIER);
208         builder.setKeyEncAlgo(WSConstants.KEYTRANSPORT_RSAOAEP);
209 
210         LOG.info("Before Encryption Triple DES/RSA-OAEP....");
211         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_128);
212         SecretKey symmetricKey = keyGen.generateKey();
213         Document encryptedDoc = builder.build(crypto, symmetricKey);
214         LOG.info("After Encryption Triple DES/RSA-OAEP....");
215 
216         String outputString =
217             XMLUtils.prettyDocumentToString(encryptedDoc);
218         if (LOG.isDebugEnabled()) {
219             LOG.debug("Encrypted message, RSA-OAEP keytransport, 3DES:");
220             LOG.debug(outputString);
221         }
222         assertFalse(outputString.contains("counter_port_type"));
223 
224         WSSecurityEngine newEngine = new WSSecurityEngine();
225         WSHandlerResult results =
226             newEngine.processSecurityHeader(encryptedDoc, null, keystoreCallbackHandler, crypto);
227 
228         WSSecurityEngineResult actionResult =
229                 results.getActionResults().get(WSConstants.ENCR).get(0);
230         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE));
231         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE));
232         REFERENCE_TYPE referenceType =
233             (REFERENCE_TYPE)actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE);
234         assertTrue(referenceType == REFERENCE_TYPE.KEY_IDENTIFIER);
235     }
236 
237     @Test
238     public void testEncryptionDecryptionPublicKey() throws Exception {
239         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
240         WSSecHeader secHeader = new WSSecHeader(doc);
241         secHeader.insertSecurityHeader();
242 
243         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
244         builder.setKeyIdentifierType(WSConstants.KEY_VALUE);
245         builder.setKeyEncAlgo(WSConstants.KEYTRANSPORT_RSAOAEP);
246 
247         CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
248         cryptoType.setAlias("wss40");
249         X509Certificate[] certs = crypto.getX509Certificates(cryptoType);
250         assertNotNull(certs);
251         builder.setUseThisPublicKey(certs[0].getPublicKey());
252 
253         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_128);
254         SecretKey symmetricKey = keyGen.generateKey();
255         Document encryptedDoc = builder.build(crypto, symmetricKey);
256 
257         String outputString =
258             XMLUtils.prettyDocumentToString(encryptedDoc);
259         if (LOG.isDebugEnabled()) {
260             LOG.debug(outputString);
261         }
262         assertFalse(outputString.contains("counter_port_type"));
263 
264         WSSecurityEngine newEngine = new WSSecurityEngine();
265         WSHandlerResult results =
266             newEngine.processSecurityHeader(encryptedDoc, null, keystoreCallbackHandler, crypto);
267 
268         WSSecurityEngineResult actionResult =
269                 results.getActionResults().get(WSConstants.ENCR).get(0);
270         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_PUBLIC_KEY));
271     }
272 
273     /**
274      * Test that encrypt and then again encrypts (Super encryption) WS-Security
275      * envelope and then verifies it <p/>
276      *
277      * @throws Exception
278      *             Thrown when there is any problem in encryption or
279      *             verification
280      */
281     @Test
282     public void testEncryptionEncryption() throws Exception {
283         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
284         WSSecHeader secHeader = new WSSecHeader(doc);
285         secHeader.insertSecurityHeader();
286 
287         Crypto encCrypto = CryptoFactory.getInstance();
288         WSSecEncrypt encrypt = new WSSecEncrypt(secHeader);
289         encrypt.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e");
290         LOG.info("Before Encryption....");
291 
292         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_128);
293         SecretKey symmetricKey = keyGen.generateKey();
294         Document encryptedDoc = encrypt.build(encCrypto, symmetricKey);
295 
296         if (LOG.isDebugEnabled()) {
297             LOG.debug("After the first encryption:");
298             String outputString =
299                 XMLUtils.prettyDocumentToString(encryptedDoc);
300             LOG.debug(outputString);
301         }
302 
303         Document encryptedEncryptedDoc = encrypt.build(encCrypto, symmetricKey);
304 
305         if (LOG.isDebugEnabled()) {
306             LOG.debug("After the second encryption:");
307             String outputString =
308                 XMLUtils.prettyDocumentToString(encryptedEncryptedDoc);
309             LOG.debug(outputString);
310         }
311 
312         LOG.info("After Encryption....");
313         verify(encryptedEncryptedDoc, encCrypto, keystoreCallbackHandler);
314     }
315 
316     /**
317      * Test that encrypts and decrypts a WS-Security envelope.
318      * The test uses the ThumbprintSHA1 key identifier type.
319      * <p/>
320      *
321      * @throws Exception Thrown when there is any problem in encryption or decryption
322      */
323     @Test
324     public void testX509EncryptionThumb() throws Exception {
325         Crypto encCrypto = CryptoFactory.getInstance();
326         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
327         WSSecHeader secHeader = new WSSecHeader(doc);
328         secHeader.insertSecurityHeader();
329 
330         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
331         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
332         builder.setKeyIdentifierType(WSConstants.THUMBPRINT_IDENTIFIER);
333 
334         LOG.info("Before Encrypting ThumbprintSHA1....");
335         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_128);
336         SecretKey symmetricKey = keyGen.generateKey();
337         Document encryptedDoc = builder.build(encCrypto, symmetricKey);
338 
339         String outputString =
340             XMLUtils.prettyDocumentToString(encryptedDoc);
341         if (LOG.isDebugEnabled()) {
342             LOG.debug("Encrypted message with THUMBPRINT_IDENTIFIER:");
343             LOG.debug(outputString);
344         }
345         assertTrue(outputString.contains("#ThumbprintSHA1"));
346 
347         LOG.info("After Encrypting ThumbprintSHA1....");
348         WSHandlerResult results = verify(encryptedDoc, encCrypto, keystoreCallbackHandler);
349 
350         WSSecurityEngineResult actionResult =
351                 results.getActionResults().get(WSConstants.ENCR).get(0);
352         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE));
353         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE));
354         REFERENCE_TYPE referenceType =
355             (REFERENCE_TYPE)actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE);
356         assertTrue(referenceType == REFERENCE_TYPE.THUMBPRINT_SHA1);
357     }
358 
359     /**
360      * Test that encrypts and decrypts a WS-Security envelope.
361      * The test uses the EncryptedKeySHA1 key identifier type.
362      * <p/>
363      *
364      * @throws Exception Thrown when there is any problem in encryption or decryption
365      */
366     @Test
367     public void testX509EncryptionSHA1() throws Exception {
368         Crypto encCrypto = CryptoFactory.getInstance();
369         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
370         WSSecHeader secHeader = new WSSecHeader(doc);
371         secHeader.insertSecurityHeader();
372 
373         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
374         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
375         builder.setKeyIdentifierType(WSConstants.ENCRYPTED_KEY_SHA1_IDENTIFIER);
376 
377         LOG.info("Before Encrypting EncryptedKeySHA1....");
378         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_128);
379         SecretKey symmetricKey = keyGen.generateKey();
380         Document encryptedDoc = builder.build(encCrypto, symmetricKey);
381 
382         String outputString =
383             XMLUtils.prettyDocumentToString(encryptedDoc);
384         if (LOG.isDebugEnabled()) {
385             LOG.debug("Encrypted message with ENCRYPTED_KEY_SHA1_IDENTIFIER:");
386             LOG.debug(outputString);
387         }
388         assertTrue(outputString.contains("#EncryptedKeySHA1"));
389 
390         LOG.info("After Encrypting EncryptedKeySHA1....");
391         verify(encryptedDoc, encCrypto, keystoreCallbackHandler);
392     }
393 
394     /**
395      * Test that encrypts using EncryptedKeySHA1, where it uses a symmetric key, rather than a
396      * generated session key which is then encrypted using a public key.
397      *
398      * @throws Exception Thrown when there is any problem in encryption or decryption
399      */
400     @Test
401     public void testEncryptionSHA1Symmetric() throws Exception {
402         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
403         WSSecHeader secHeader = new WSSecHeader(doc);
404         secHeader.insertSecurityHeader();
405 
406         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
407         builder.setKeyIdentifierType(WSConstants.ENCRYPTED_KEY_SHA1_IDENTIFIER);
408         builder.setEncryptSymmKey(false);
409 
410         LOG.info("Before Encrypting EncryptedKeySHA1....");
411         Document encryptedDoc = builder.build(crypto, key);
412 
413         byte[] encodedBytes = KeyUtils.generateDigest(keyData);
414         String identifier = org.apache.xml.security.utils.XMLUtils.encodeToString(encodedBytes);
415         secretKeyCallbackHandler.addSecretKey(identifier, keyData);
416 
417         String outputString =
418             XMLUtils.prettyDocumentToString(encryptedDoc);
419         if (LOG.isDebugEnabled()) {
420             LOG.debug("Encrypted message with ENCRYPTED_KEY_SHA1_IDENTIFIER:");
421             LOG.debug(outputString);
422         }
423         assertTrue(outputString.contains("#EncryptedKeySHA1"));
424 
425         LOG.info("After Encrypting EncryptedKeySHA1....");
426         verify(encryptedDoc, null, secretKeyCallbackHandler);
427     }
428 
429     /**
430      * Test that encrypts using EncryptedKeySHA1, where it uses a symmetric key, rather than a
431      * generated session key which is then encrypted using a public key. The request is generated
432      * using WSHandler, instead of coding it.
433      *
434      * @throws Exception Thrown when there is any problem in encryption or decryption
435      */
436     @Test
437     public void testEncryptionSHA1SymmetricBytesHandler() throws Exception {
438         final WSSConfig cfg = WSSConfig.getNewInstance();
439         final RequestData reqData = new RequestData();
440         reqData.setWssConfig(cfg);
441         java.util.Map<String, Object> messageContext = new java.util.TreeMap<>();
442         messageContext.put(WSHandlerConstants.ENC_SYM_ENC_KEY, "false");
443         messageContext.put(WSHandlerConstants.ENC_KEY_ID, "EncryptedKeySHA1");
444         secretKeyCallbackHandler.setOutboundSecret(keyData);
445         messageContext.put(WSHandlerConstants.PW_CALLBACK_REF, secretKeyCallbackHandler);
446         reqData.setMsgContext(messageContext);
447         reqData.setUsername("");
448 
449         final Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
450         CustomHandler handler = new CustomHandler();
451         HandlerAction action = new HandlerAction(WSConstants.ENCR);
452         handler.send(
453             doc,
454             reqData,
455             Collections.singletonList(action),
456             true
457         );
458 
459         String outputString =
460             XMLUtils.prettyDocumentToString(doc);
461         if (LOG.isDebugEnabled()) {
462             LOG.debug(outputString);
463         }
464 
465         verify(doc, null, secretKeyCallbackHandler);
466     }
467 
468     /**
469      * Test that encrypt and decrypt a WS-Security envelope.
470      *
471      * This test uses the RSA_15 algorithm to transport (wrap) the symmetric key.
472      * The test case creates a ReferenceList element that references EncryptedData
473      * elements. The ReferencesList element is put into the Security header, not
474      * as child of the EncryptedKey. The EncryptedData elements contain a KeyInfo
475      * that references the EncryptedKey via a STR/Reference structure.
476      *
477      * Refer to OASIS WS Security spec 1.1, chap 7.7
478      */
479     @Test
480     public void testEncryptionDecryptionRSA15STR() throws Exception {
481         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
482         WSSecHeader secHeader = new WSSecHeader(doc);
483         secHeader.insertSecurityHeader();
484 
485         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
486         builder.setUserInfo("wss40");
487         builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
488         builder.setSymmetricEncAlgorithm(WSConstants.TRIPLE_DES);
489         LOG.info("Before Encryption Triple DES....");
490 
491         /*
492          * Prepare the Encrypt object with the token, setup data structure
493          */
494         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.TRIPLE_DES);
495         SecretKey symmetricKey = keyGen.generateKey();
496         builder.prepare(crypto, symmetricKey);
497 
498         /*
499          * Set up the parts structure to encrypt the body
500          */
501         SOAPConstants soapConstants = WSSecurityUtil.getSOAPConstants(doc
502                 .getDocumentElement());
503         WSEncryptionPart encP = new WSEncryptionPart(soapConstants
504                 .getBodyQName().getLocalPart(), soapConstants.getEnvelopeURI(),
505                 "Content");
506         builder.getParts().add(encP);
507 
508         /*
509          * Encrypt the parts (Body), create EncryptedData elements that reference
510          * the EncryptedKey, and get a ReferenceList that can be put into the
511          * Security header. Be sure that the ReferenceList is after the
512          * EncryptedKey element in the Security header (strict layout)
513          */
514         Element refs = builder.encrypt(symmetricKey);
515         builder.addExternalRefElement(refs);
516 
517         /*
518          * now add (prepend) the EncryptedKey element, then a
519          * BinarySecurityToken if one was setup during prepare
520          */
521         builder.prependToHeader();
522 
523         builder.prependBSTElementToHeader();
524 
525         Document encryptedDoc = doc;
526         LOG.info("After Encryption Triple DES....");
527 
528         String outputString =
529             XMLUtils.prettyDocumentToString(encryptedDoc);
530         if (LOG.isDebugEnabled()) {
531             LOG.debug("Encrypted message, RSA-15 keytransport, 3DES:");
532             LOG.debug(outputString);
533         }
534         assertFalse(outputString.contains("counter_port_type"));
535         WSHandlerResult results = verify(encryptedDoc, crypto, keystoreCallbackHandler);
536 
537         outputString =
538             XMLUtils.prettyDocumentToString(encryptedDoc);
539         assertTrue(outputString.contains("counter_port_type"));
540 
541         WSSecurityEngineResult actionResult =
542                 results.getActionResults().get(WSConstants.ENCR).get(0);
543         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE));
544         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE));
545         REFERENCE_TYPE referenceType =
546             (REFERENCE_TYPE)actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE);
547         assertTrue(referenceType == REFERENCE_TYPE.DIRECT_REF);
548     }
549 
550 
551     @Test
552     public void testBadAttribute() throws Exception {
553         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
554         WSSecHeader secHeader = new WSSecHeader(doc);
555         secHeader.insertSecurityHeader();
556 
557         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
558         builder.setUserInfo("wss40");
559         builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
560         builder.setSymmetricEncAlgorithm(WSConstants.TRIPLE_DES);
561 
562         /*
563          * Prepare the Encrypt object with the token, setup data structure
564          */
565         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.TRIPLE_DES);
566         SecretKey symmetricKey = keyGen.generateKey();
567         builder.prepare(crypto, symmetricKey);
568 
569         /*
570          * Set up the parts structure to encrypt the body
571          */
572         SOAPConstants soapConstants = WSSecurityUtil.getSOAPConstants(doc
573                 .getDocumentElement());
574         java.util.List<WSEncryptionPart> parts = new ArrayList<>();
575         WSEncryptionPart encP = new WSEncryptionPart(soapConstants
576                 .getBodyQName().getLocalPart(), soapConstants.getEnvelopeURI(),
577                 "Content");
578         parts.add(encP);
579 
580         /*
581          * Encrypt the parts (Body), create EncryptedData elements that reference
582          * the EncryptedKey, and get a ReferenceList that can be put into the
583          * Security header. Be sure that the ReferenceList is after the
584          * EncryptedKey element in the Security header (strict layout)
585          */
586         Element refs = builder.encrypt(symmetricKey);
587         builder.addExternalRefElement(refs);
588 
589         /*
590          * now add (prepend) the EncryptedKey element, then a
591          * BinarySecurityToken if one was setup during prepare
592          */
593         Element encryptedKeyElement = builder.getEncryptedKeyElement();
594         encryptedKeyElement.setAttributeNS(null, "Type", "SomeType");
595         WSSecurityUtil.prependChildElement(secHeader.getSecurityHeaderElement(), encryptedKeyElement);
596 
597         builder.prependBSTElementToHeader();
598 
599         Document encryptedDoc = doc;
600 
601         String outputString =
602             XMLUtils.prettyDocumentToString(encryptedDoc);
603         if (LOG.isDebugEnabled()) {
604             LOG.debug(outputString);
605         }
606 
607         WSSecurityEngine newEngine = new WSSecurityEngine();
608         try {
609             newEngine.processSecurityHeader(encryptedDoc, null, keystoreCallbackHandler, crypto);
610             fail("Failure expected on a bad attribute type");
611         } catch (WSSecurityException ex) {
612             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
613         }
614 
615         RequestData data = new RequestData();
616         data.setCallbackHandler(keystoreCallbackHandler);
617         data.setDecCrypto(crypto);
618         data.setIgnoredBSPRules(Collections.singletonList(BSPRule.R3209));
619         newEngine.processSecurityHeader(encryptedDoc, data);
620     }
621 
622     /**
623      * In this test an EncryptedKey structure is embedded in the EncryptedData structure.
624      * The EncryptedKey structure refers to a certificate via the SKI_KEY_IDENTIFIER.
625      */
626     @Test
627     public void testEmbeddedEncryptedKey() throws Exception {
628         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
629         WSSecHeader secHeader = new WSSecHeader(doc);
630         secHeader.insertSecurityHeader();
631 
632         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
633         builder.setUserInfo("wss40");
634         builder.setKeyIdentifierType(WSConstants.SKI_KEY_IDENTIFIER);
635         builder.setSymmetricEncAlgorithm(WSConstants.AES_128);
636 
637         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_128);
638         SecretKey symmetricKey = keyGen.generateKey();
639         builder.prepare(crypto, symmetricKey);
640         builder.setEmbedEncryptedKey(true);
641 
642         SOAPConstants soapConstants = WSSecurityUtil.getSOAPConstants(doc
643                 .getDocumentElement());
644         java.util.List<WSEncryptionPart> parts = new ArrayList<>();
645         WSEncryptionPart encP = new WSEncryptionPart(soapConstants
646                 .getBodyQName().getLocalPart(), soapConstants.getEnvelopeURI(),
647                 "Content");
648         parts.add(encP);
649 
650         builder.encrypt(symmetricKey);
651 
652         String outputString =
653             XMLUtils.prettyDocumentToString(doc);
654         if (LOG.isDebugEnabled()) {
655             LOG.debug(outputString);
656         }
657 
658         verify(doc, crypto, keystoreCallbackHandler);
659     }
660 
661     /**
662      * Test that encrypt and decrypt a WS-Security envelope.
663      * This test uses the RSA OAEP algorithm to transport (wrap) the symmetric
664      * key and SHA-256.
665      * <p/>
666      *
667      * @throws Exception Thrown when there is any problem in signing or verification
668      */
669     @Test
670     public void testEncryptionDecryptionOAEPSHA256() throws Exception {
671         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
672         WSSecHeader secHeader = new WSSecHeader(doc);
673         secHeader.insertSecurityHeader();
674 
675         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
676         builder.setUserInfo("wss40");
677         builder.setKeyEncAlgo(WSConstants.KEYTRANSPORT_RSAOAEP);
678         builder.setDigestAlgorithm(WSConstants.SHA256);
679 
680         LOG.info("Before Encryption Triple DES/RSA-OAEP....");
681         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_128);
682         SecretKey symmetricKey = keyGen.generateKey();
683         Document encryptedDoc = builder.build(crypto, symmetricKey);
684         LOG.info("After Encryption Triple DES/RSA-OAEP....");
685 
686         String outputString =
687             XMLUtils.prettyDocumentToString(encryptedDoc);
688         if (LOG.isDebugEnabled()) {
689             LOG.debug("Encrypted message, RSA-OAEP keytransport, 3DES:");
690             LOG.debug(outputString);
691         }
692         assertFalse(outputString.contains("counter_port_type"));
693 
694         WSSecurityEngine newEngine = new WSSecurityEngine();
695         WSHandlerResult results =
696             newEngine.processSecurityHeader(encryptedDoc, null, keystoreCallbackHandler, crypto);
697 
698         WSSecurityEngineResult actionResult =
699                 results.getActionResults().get(WSConstants.ENCR).get(0);
700         assertNotNull(actionResult);
701     }
702 
703     // CN has a "*" in it
704     @Test
705     public void testEncryptionWithRegexpCert() throws Exception {
706         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
707         WSSecHeader secHeader = new WSSecHeader(doc);
708         secHeader.insertSecurityHeader();
709 
710         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
711         builder.setUserInfo("regexp");
712         builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
713         builder.setKeyEncAlgo(WSConstants.KEYTRANSPORT_RSAOAEP);
714         LOG.info("Before Encryption Triple DES/RSA-OAEP....");
715 
716         Crypto regexpCrypto = CryptoFactory.getInstance("regexp.properties");
717         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_128);
718         SecretKey symmetricKey = keyGen.generateKey();
719         Document encryptedDoc = builder.build(regexpCrypto, symmetricKey);
720         LOG.info("After Encryption Triple DES/RSA-OAEP....");
721 
722         String outputString =
723             XMLUtils.prettyDocumentToString(encryptedDoc);
724         if (LOG.isDebugEnabled()) {
725             LOG.debug("Encrypted message, RSA-OAEP keytransport, 3DES:");
726             LOG.debug(outputString);
727         }
728         assertFalse(outputString.contains("counter_port_type"));
729 
730         WSSecurityEngine newEngine = new WSSecurityEngine();
731         newEngine.processSecurityHeader(encryptedDoc, null, keystoreCallbackHandler, regexpCrypto);
732     }
733 
734     /**
735      * Verifies the soap envelope <p/>
736      *
737      * @param doc
738      * @param decCrypto
739      * @param handler
740      * @throws Exception
741      *             Thrown when there is a problem in verification
742      */
743     private WSHandlerResult verify(
744         Document doc, Crypto decCrypto, CallbackHandler handler
745     ) throws Exception {
746         WSHandlerResult results =
747             secEngine.processSecurityHeader(doc, null, handler, decCrypto);
748         if (LOG.isDebugEnabled()) {
749             String outputString =
750                 XMLUtils.prettyDocumentToString(doc);
751             LOG.debug(outputString);
752         }
753         return results;
754     }
755 
756     /**
757      * Verifies the soap envelope
758      * <p/>
759      *
760      * @param doc
761      * @param handler
762      * @param expectedEncryptedElement
763      * @throws Exception Thrown when there is a problem in verification
764      */
765     @SuppressWarnings("unchecked")
766     private WSHandlerResult verify(
767         Document doc,
768         CallbackHandler handler,
769         javax.xml.namespace.QName expectedEncryptedElement
770     ) throws Exception {
771         final WSHandlerResult results =
772             secEngine.processSecurityHeader(doc, null, handler, null, crypto);
773         String outputString =
774             XMLUtils.prettyDocumentToString(doc);
775         if (LOG.isDebugEnabled()) {
776             LOG.debug(outputString);
777         }
778         assertTrue(outputString.indexOf("counter_port_type") > 0 ? true : false);
779         //
780         // walk through the results, and make sure there is an encryption
781         // action, together with a reference to the decrypted element
782         // (as a QName)
783         //
784         boolean encrypted = false;
785         for (WSSecurityEngineResult result : results.getResults()) {
786             final Integer action = (Integer) result.get(WSSecurityEngineResult.TAG_ACTION);
787             assertNotNull(action);
788             if ((action & WSConstants.ENCR) != 0) {
789                 final java.util.List<WSDataRef> refs =
790                     (java.util.List<WSDataRef>) result.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
791                 assertNotNull(refs);
792                 encrypted = true;
793                 for (WSDataRef ref : refs) {
794                     assertNotNull(ref.getName());
795                     assertEquals(
796                         expectedEncryptedElement,
797                         ref.getName()
798                     );
799                     assertNotNull(ref.getProtectedElement());
800                     if (LOG.isDebugEnabled()) {
801                         LOG.debug("WSDataRef element: ");
802                         LOG.debug(
803                             DOM2Writer.nodeToString(ref.getProtectedElement())
804                         );
805                     }
806                 }
807             }
808         }
809         assertTrue(encrypted);
810         return results;
811     }
812 
813 }