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  package org.apache.wss4j.stax.impl.processor.output;
20  
21  import java.io.OutputStream;
22  import java.lang.reflect.Constructor;
23  import java.lang.reflect.InvocationTargetException;
24  import java.security.spec.AlgorithmParameterSpec;
25  import java.util.ArrayList;
26  import java.util.HashMap;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.Map;
30  
31  import javax.crypto.Cipher;
32  import javax.security.auth.callback.Callback;
33  import javax.security.auth.callback.CallbackHandler;
34  import javax.xml.namespace.QName;
35  import javax.xml.stream.XMLStreamConstants;
36  import javax.xml.stream.XMLStreamException;
37  import javax.xml.stream.events.Attribute;
38  
39  import org.apache.wss4j.common.ext.Attachment;
40  import org.apache.wss4j.common.ext.AttachmentRequestCallback;
41  import org.apache.wss4j.common.ext.AttachmentResultCallback;
42  import org.apache.wss4j.common.ext.WSSecurityException;
43  import org.apache.wss4j.common.util.AttachmentUtils;
44  import org.apache.wss4j.stax.ext.WSSConstants;
45  import org.apache.wss4j.stax.ext.WSSSecurityProperties;
46  import org.apache.wss4j.stax.securityToken.WSSecurityTokenConstants;
47  import org.apache.wss4j.stax.utils.WSSUtils;
48  import org.apache.xml.security.algorithms.JCEMapper;
49  import org.apache.xml.security.encryption.XMLCipherUtil;
50  import org.apache.xml.security.exceptions.XMLSecurityException;
51  import org.apache.xml.security.stax.config.JCEAlgorithmMapper;
52  import org.apache.xml.security.stax.config.TransformerAlgorithmMapper;
53  import org.apache.xml.security.stax.ext.OutputProcessorChain;
54  import org.apache.xml.security.stax.ext.SecurePart;
55  import org.apache.xml.security.stax.ext.SecurePart.Modifier;
56  import org.apache.xml.security.stax.ext.XMLSecurityConstants;
57  import org.apache.xml.security.stax.ext.stax.XMLSecAttribute;
58  import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
59  import org.apache.xml.security.stax.ext.stax.XMLSecStartElement;
60  import org.apache.xml.security.stax.impl.EncryptionPartDef;
61  import org.apache.xml.security.stax.impl.processor.output.AbstractEncryptOutputProcessor;
62  import org.apache.xml.security.stax.impl.util.IDGenerator;
63  import org.apache.xml.security.stax.securityToken.OutboundSecurityToken;
64  import org.apache.xml.security.stax.securityToken.SecurityTokenConstants.KeyIdentifier;
65  import org.apache.xml.security.stax.securityToken.SecurityTokenProvider;
66  
67  /**
68   * Processor to encrypt XML structures
69   */
70  public class EncryptOutputProcessor extends AbstractEncryptOutputProcessor {
71  
72      private static final org.slf4j.Logger LOG =
73          org.slf4j.LoggerFactory.getLogger(EncryptOutputProcessor.class);
74  
75      public EncryptOutputProcessor() throws XMLSecurityException {
76          super();
77      }
78  
79      @Override
80      public void init(OutputProcessorChain outputProcessorChain) throws XMLSecurityException {
81          super.init(outputProcessorChain);
82          EncryptEndingOutputProcessor encryptEndingOutputProcessor = new EncryptEndingOutputProcessor();
83          encryptEndingOutputProcessor.setXMLSecurityProperties(getSecurityProperties());
84          encryptEndingOutputProcessor.setAction(getAction(), getActionOrder());
85          encryptEndingOutputProcessor.init(outputProcessorChain);
86      }
87  
88      @Override
89      public void processEvent(XMLSecEvent xmlSecEvent, OutputProcessorChain outputProcessorChain)
90          throws XMLStreamException, XMLSecurityException {
91          if (xmlSecEvent.getEventType() == XMLStreamConstants.START_ELEMENT) {
92              XMLSecStartElement xmlSecStartElement = xmlSecEvent.asStartElement();
93  
94              //avoid double encryption when child elements matches too
95              if (getActiveInternalEncryptionOutputProcessor() == null) {
96                  SecurePart securePart = securePartMatches(xmlSecStartElement, outputProcessorChain, WSSConstants.ENCRYPTION_PARTS);
97                  if (securePart != null) {
98                      LOG.debug("Matched encryptionPart for encryption");
99                      InternalEncryptionOutputProcessor internalEncryptionOutputProcessor;
100                     String tokenId = outputProcessorChain.getSecurityContext().get(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_ENCRYPTION);
101                     SecurityTokenProvider<OutboundSecurityToken> securityTokenProvider =
102                         outputProcessorChain.getSecurityContext().getSecurityTokenProvider(tokenId);
103                     OutboundSecurityToken securityToken = securityTokenProvider.getSecurityToken();
104                     EncryptionPartDef encryptionPartDef = new EncryptionPartDef();
105                     encryptionPartDef.setSecurePart(securePart);
106                     encryptionPartDef.setModifier(securePart.getModifier());
107                     encryptionPartDef.setEncRefId(IDGenerator.generateID(null));
108 
109                     Map<Object, SecurePart> dynamicSecureParts =
110                         outputProcessorChain.getSecurityContext().getAsMap(WSSConstants.SIGNATURE_PARTS);
111                     if (dynamicSecureParts != null && securePart.getName() != null
112                         && securePart.equals(dynamicSecureParts.get(securePart.getName()))) {
113                         securePart.setIdToSecure(encryptionPartDef.getEncRefId());
114                         outputProcessorChain.getSecurityContext().putAsMap(
115                             WSSConstants.SIGNATURE_PARTS,
116                             securePart.getIdToSecure(),
117                             securePart
118                         );
119                     }
120 
121                     encryptionPartDef.setKeyId(securityTokenProvider.getId());
122                     encryptionPartDef.setSymmetricKey(securityToken.getSecretKey(getSecurityProperties().getEncryptionSymAlgorithm()));
123                     outputProcessorChain.getSecurityContext().putAsList(EncryptionPartDef.class, encryptionPartDef);
124                     internalEncryptionOutputProcessor =
125                             new InternalEncryptionOutputProcessor(
126                                     encryptionPartDef,
127                                     xmlSecStartElement,
128                                     outputProcessorChain.getDocumentContext().getEncoding(),
129                                     securityToken
130                             );
131                     internalEncryptionOutputProcessor.setXMLSecurityProperties(getSecurityProperties());
132                     internalEncryptionOutputProcessor.setAction(getAction(), getActionOrder());
133                     internalEncryptionOutputProcessor.init(outputProcessorChain);
134 
135                     setActiveInternalEncryptionOutputProcessor(internalEncryptionOutputProcessor);
136 
137                     //we can remove this processor when the whole body will be encrypted since there is
138                     //nothing more which can be encrypted.
139                     if (WSSConstants.TAG_SOAP_BODY_LN.equals(xmlSecStartElement.getName().getLocalPart())
140                             && WSSUtils.isInSOAPBody(xmlSecStartElement)) {
141                         doFinalInternal(outputProcessorChain);
142                         outputProcessorChain.removeProcessor(this);
143                     }
144                 }
145             }
146         }
147 
148         outputProcessorChain.processEvent(xmlSecEvent);
149     }
150 
151     @Override
152     protected SecurePart securePartMatches(XMLSecStartElement xmlSecStartElement, Map<Object, SecurePart> secureParts) {
153 
154         if (!xmlSecStartElement.getOnElementDeclaredAttributes().isEmpty()) {
155             Attribute attribute = xmlSecStartElement.getAttributeByName(WSSConstants.ATT_WSU_ID);
156             if (attribute != null) {
157                 SecurePart securePart = secureParts.get(attribute.getValue());
158                 if (securePart != null) {
159                     return securePart;
160                 }
161             }
162             attribute = xmlSecStartElement.getAttributeByName(WSSConstants.ATT_NULL_Id);
163             if (attribute != null) {
164                 SecurePart securePart = secureParts.get(attribute.getValue());
165                 if (securePart != null) {
166                     return securePart;
167                 }
168             }
169             attribute = xmlSecStartElement.getAttributeByName(WSSConstants.ATT_NULL_ID);
170             if (attribute != null) {
171                 SecurePart securePart = secureParts.get(attribute.getValue());
172                 if (securePart != null) {
173                     return securePart;
174                 }
175             }
176             attribute = xmlSecStartElement.getAttributeByName(WSSConstants.ATT_NULL_ASSERTION_ID);
177             if (attribute != null) {
178                 SecurePart securePart = secureParts.get(attribute.getValue());
179                 if (securePart != null) {
180                     return securePart;
181                 }
182             }
183         }
184 
185         return secureParts.get(xmlSecStartElement.getName());
186     }
187 
188     @Override
189     public void doFinalInternal(OutputProcessorChain outputProcessorChain) throws XMLSecurityException {
190         setupAttachmentEncryptionStreams(outputProcessorChain);
191         super.doFinalInternal(outputProcessorChain);
192     }
193 
194     protected void setupAttachmentEncryptionStreams(OutputProcessorChain outputProcessorChain) throws XMLSecurityException {
195 
196         SecurePart attachmentSecurePart = null;
197 
198         Map<Object, SecurePart> dynamicSecureParts =
199             outputProcessorChain.getSecurityContext().getAsMap(XMLSecurityConstants.ENCRYPTION_PARTS);
200         Iterator<Map.Entry<Object, SecurePart>> securePartsMapIterator = dynamicSecureParts.entrySet().iterator();
201         String externalId = "";
202         while (securePartsMapIterator.hasNext()) {
203             Map.Entry<Object, SecurePart> securePartEntry = securePartsMapIterator.next();
204             final SecurePart securePart = securePartEntry.getValue();
205             final String externalReference = securePart.getExternalReference();
206             if (externalReference != null && externalReference.startsWith("cid:")) {
207                 attachmentSecurePart = securePart;
208                 externalId = AttachmentUtils.getAttachmentId(externalReference);
209                 break;
210             }
211         }
212         if (attachmentSecurePart == null) {
213             return;
214         }
215 
216         CallbackHandler attachmentCallbackHandler =
217                 ((WSSSecurityProperties) getSecurityProperties()).getAttachmentCallbackHandler();
218         if (attachmentCallbackHandler == null) {
219             throw new WSSecurityException(
220                     WSSecurityException.ErrorCode.FAILURE,
221                     "empty", new Object[] {"no attachment callbackhandler supplied"}
222             );
223         }
224 
225         AttachmentRequestCallback attachmentRequestCallback = new AttachmentRequestCallback();
226         attachmentRequestCallback.setAttachmentId(externalId);
227         try {
228             attachmentCallbackHandler.handle(new Callback[]{attachmentRequestCallback});
229         } catch (Exception e) {
230             throw new WSSecurityException(
231                     WSSecurityException.ErrorCode.FAILURE, e
232             );
233         }
234 
235         List<Attachment> attachments = attachmentRequestCallback.getAttachments();
236         if (attachments != null) {
237             for (int i = 0; i < attachments.size(); i++) {
238                 final Attachment attachment = attachments.get(i);
239                 final String attachmentId = attachment.getId();
240 
241                 String tokenId = outputProcessorChain.getSecurityContext().get(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_ENCRYPTION);
242                 SecurityTokenProvider<OutboundSecurityToken> securityTokenProvider =
243                         outputProcessorChain.getSecurityContext().getSecurityTokenProvider(tokenId);
244                 OutboundSecurityToken securityToken = securityTokenProvider.getSecurityToken();
245                 EncryptionPartDef encryptionPartDef = new EncryptionPartDef();
246                 encryptionPartDef.setSecurePart(attachmentSecurePart);
247                 encryptionPartDef.setModifier(attachmentSecurePart.getModifier());
248                 encryptionPartDef.setCipherReferenceId(attachment.getId());
249                 encryptionPartDef.setMimeType(attachment.getMimeType());
250                 encryptionPartDef.setEncRefId(IDGenerator.generateID(null));
251                 encryptionPartDef.setKeyId(securityTokenProvider.getId());
252                 encryptionPartDef.setSymmetricKey(securityToken.getSecretKey(getSecurityProperties().getEncryptionSymAlgorithm()));
253                 outputProcessorChain.getSecurityContext().putAsList(EncryptionPartDef.class, encryptionPartDef);
254 
255                 final Attachment resultAttachment = new Attachment();
256                 resultAttachment.setId(attachmentId);
257                 resultAttachment.setMimeType("application/octet-stream");
258 
259                 String encryptionSymAlgorithm = getSecurityProperties().getEncryptionSymAlgorithm();
260                 String jceAlgorithm = JCEAlgorithmMapper.translateURItoJCEID(encryptionSymAlgorithm);
261                 if (jceAlgorithm == null) {
262                     throw new XMLSecurityException("algorithms.NoSuchMap", new Object[] {encryptionSymAlgorithm});
263                 }
264                 //initialize the cipher
265                 Cipher cipher = null;
266                 try {
267                     cipher = Cipher.getInstance(jceAlgorithm);
268 
269                     int ivLen = JCEMapper.getIVLengthFromURI(encryptionSymAlgorithm) / 8;
270                     byte[] iv = XMLSecurityConstants.generateBytes(ivLen);
271                     AlgorithmParameterSpec paramSpec =
272                         XMLCipherUtil.constructBlockCipherParameters(encryptionSymAlgorithm, iv);
273                     cipher.init(Cipher.ENCRYPT_MODE, encryptionPartDef.getSymmetricKey(), paramSpec);
274 
275                 } catch (Exception e) {
276                     throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_ENCRYPTION, e);
277                 }
278 
279                 final Map<String, String> headers = new HashMap<>();
280                 headers.putAll(attachment.getHeaders());
281                 resultAttachment.setSourceStream(
282                         AttachmentUtils.setupAttachmentEncryptionStream(
283                                 cipher,
284                                 SecurePart.Modifier.Element == encryptionPartDef.getModifier(),
285                                 attachment, headers
286                         ));
287                 resultAttachment.addHeaders(headers);
288 
289                 final AttachmentResultCallback attachmentResultCallback = new AttachmentResultCallback();
290                 attachmentResultCallback.setAttachmentId(attachmentId);
291                 attachmentResultCallback.setAttachment(resultAttachment);
292                 try {
293                     attachmentCallbackHandler.handle(new Callback[]{attachmentResultCallback});
294                 } catch (Exception e) {
295                     throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_ENCRYPTION, e);
296                 }
297             }
298         }
299     }
300 
301     /**
302      * Processor which handles the effective encryption of the data
303      */
304     class InternalEncryptionOutputProcessor extends AbstractInternalEncryptionOutputProcessor {
305 
306         private boolean doEncryptedHeader = false;
307         private final OutboundSecurityToken securityToken;
308 
309         InternalEncryptionOutputProcessor(EncryptionPartDef encryptionPartDef, XMLSecStartElement xmlSecStartElement,
310                                           String encoding, OutboundSecurityToken securityToken)
311                 throws XMLSecurityException, XMLStreamException {
312 
313             super(encryptionPartDef, xmlSecStartElement, encoding);
314             this.addBeforeProcessor(EncryptEndingOutputProcessor.class);
315             this.addBeforeProcessor(InternalEncryptionOutputProcessor.class);
316             this.addAfterProcessor(EncryptOutputProcessor.class);
317             this.securityToken = securityToken;
318         }
319 
320         protected OutputStream applyTransforms(OutputStream outputStream) throws XMLSecurityException {
321             String compressionAlgorithm = ((WSSSecurityProperties)getSecurityProperties()).getEncryptionCompressionAlgorithm();
322             if (compressionAlgorithm != null) {
323                 @SuppressWarnings("unchecked")
324                 Class<OutputStream> transformerClass =
325                         (Class<OutputStream>) TransformerAlgorithmMapper.getTransformerClass(
326                                 compressionAlgorithm, XMLSecurityConstants.DIRECTION.OUT
327                         );
328                 try {
329                     Constructor<OutputStream> constructor = transformerClass.getConstructor(OutputStream.class);
330                     outputStream = constructor.newInstance(outputStream);
331                 } catch (InvocationTargetException | NoSuchMethodException
332                     | InstantiationException | IllegalAccessException e) {
333                     throw new XMLSecurityException(e);
334                 }
335             }
336             return outputStream;
337         }
338 
339         /**
340          * Creates the Data structure around the cipher data
341          */
342         @Override
343         protected void processEventInternal(XMLSecStartElement xmlSecStartElement, OutputProcessorChain outputProcessorChain)
344             throws XMLStreamException, XMLSecurityException {
345 
346             List<QName> elementPath = xmlSecStartElement.getElementPath();
347 
348             //WSS 1.1 EncryptedHeader Element:
349             if (elementPath.size() == 3 && WSSUtils.isInSOAPHeader(elementPath)
350                 && Modifier.Content != super.getEncryptionPartDef().getModifier()) {
351                 doEncryptedHeader = true;
352 
353                 List<XMLSecAttribute> attributes = new ArrayList<>(1);
354 
355                 final String actor = ((WSSSecurityProperties) getSecurityProperties()).getActor();
356                 final String soapMessageVersion = WSSUtils.getSOAPMessageVersionNamespace(xmlSecStartElement);
357                 if (actor != null && !actor.isEmpty()) {
358                     if (WSSConstants.NS_SOAP11.equals(soapMessageVersion)) {
359                         attributes.add(createAttribute(WSSConstants.ATT_SOAP11_ACTOR, actor));
360                     } else {
361                         attributes.add(createAttribute(WSSConstants.ATT_SOAP12_ROLE, actor));
362                     }
363                 }
364 
365                 boolean mustUnderstand = ((WSSSecurityProperties) getSecurityProperties()).isMustUnderstand();
366                 if (mustUnderstand) {
367                     if (WSSConstants.NS_SOAP11.equals(soapMessageVersion)) {
368                         attributes.add(createAttribute(WSSConstants.ATT_SOAP11_MUST_UNDERSTAND, "1"));
369                     } else {
370                         attributes.add(createAttribute(WSSConstants.ATT_SOAP12_MUST_UNDERSTAND, "true"));
371                     }
372                 }
373 
374                 createStartElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_wsse11_EncryptedHeader, true, attributes);
375             }
376 
377             super.processEventInternal(xmlSecStartElement, outputProcessorChain);
378         }
379 
380         @Override
381         protected void createKeyInfoStructure(OutputProcessorChain outputProcessorChain)
382             throws XMLStreamException, XMLSecurityException {
383             createStartElementAndOutputAsEvent(outputProcessorChain, XMLSecurityConstants.TAG_dsig_KeyInfo, true, null);
384 
385             if (securityToken.getCustomTokenReference() != null) {
386                 outputDOMElement(securityToken.getCustomTokenReference(), outputProcessorChain);
387                 createEndElementAndOutputAsEvent(outputProcessorChain, XMLSecurityConstants.TAG_dsig_KeyInfo);
388                 return;
389             }
390 
391             KeyIdentifier keyIdentifier = ((WSSSecurityProperties) getSecurityProperties()).getEncryptionKeyIdentifier();
392             if (WSSecurityTokenConstants.KEYIDENTIFIER_ENCRYPTED_KEY_SHA1_IDENTIFIER.equals(keyIdentifier)) {
393                 List<XMLSecAttribute> attributes = new ArrayList<>(1);
394                 attributes.add(createAttribute(WSSConstants.ATT_WSSE11_TOKEN_TYPE, WSSConstants.NS_WSS_ENC_KEY_VALUE_TYPE));
395                 createStartElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_SECURITY_TOKEN_REFERENCE,
396                                                    false, attributes);
397 
398                 if (securityToken.getSha1Identifier() != null) {
399                     WSSUtils.createEncryptedKeySha1IdentifierStructure(this, outputProcessorChain,
400                                                                        securityToken.getSha1Identifier());
401                 } else {
402                     WSSUtils.createEncryptedKeySha1IdentifierStructure(this, outputProcessorChain,
403                                                                        getEncryptionPartDef().getSymmetricKey());
404                 }
405             } else if (WSSecurityTokenConstants.KEYIDENTIFIER_KERBEROS_SHA1_IDENTIFIER.equals(keyIdentifier)) {
406                 List<XMLSecAttribute> attributes = new ArrayList<>(1);
407                 attributes.add(createAttribute(WSSConstants.ATT_WSSE11_TOKEN_TYPE, WSSConstants.NS_KERBEROS5_AP_REQ));
408                 createStartElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_SECURITY_TOKEN_REFERENCE,
409                                                    false, attributes);
410 
411                 WSSUtils.createKerberosSha1IdentifierStructure(this, outputProcessorChain,
412                                                                securityToken.getSha1Identifier());
413             } else {
414                 boolean isSAMLToken = false;
415                 if (WSSecurityTokenConstants.KERBEROS_TOKEN.equals(securityToken.getTokenType())) {
416                     List<XMLSecAttribute> attributes = new ArrayList<>(2);
417                     attributes.add(createAttribute(WSSConstants.ATT_WSU_ID, IDGenerator.generateID(null)));
418                     attributes.add(createAttribute(WSSConstants.ATT_WSSE11_TOKEN_TYPE, WSSConstants.NS_GSS_KERBEROS5_AP_REQ));
419                     createStartElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_SECURITY_TOKEN_REFERENCE,
420                                                        false, attributes);
421                 } else if (WSSecurityTokenConstants.SAML_10_TOKEN.equals(securityToken.getTokenType())
422                     || WSSecurityTokenConstants.SAML_11_TOKEN.equals(securityToken.getTokenType())) {
423                     List<XMLSecAttribute> attributes = new ArrayList<>(2);
424                     attributes.add(createAttribute(WSSConstants.ATT_WSU_ID, IDGenerator.generateID(null)));
425                     attributes.add(createAttribute(WSSConstants.ATT_WSSE11_TOKEN_TYPE, WSSConstants.NS_SAML11_TOKEN_PROFILE_TYPE));
426                     createStartElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_SECURITY_TOKEN_REFERENCE,
427                                                        false, attributes);
428                     isSAMLToken = true;
429                 } else if (WSSecurityTokenConstants.SAML_20_TOKEN.equals(securityToken.getTokenType())) {
430                     List<XMLSecAttribute> attributes = new ArrayList<>(2);
431                     attributes.add(createAttribute(WSSConstants.ATT_WSU_ID, IDGenerator.generateID(null)));
432                     attributes.add(createAttribute(WSSConstants.ATT_WSSE11_TOKEN_TYPE, WSSConstants.NS_SAML20_TOKEN_PROFILE_TYPE));
433                     createStartElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_SECURITY_TOKEN_REFERENCE,
434                                                        false, attributes);
435                     isSAMLToken = true;
436                 } else if (WSSecurityTokenConstants.EncryptedKeyToken.equals(securityToken.getTokenType())) {
437                     List<XMLSecAttribute> attributes = new ArrayList<>(2);
438                     attributes.add(createAttribute(WSSConstants.ATT_WSU_ID, IDGenerator.generateID(null)));
439                     attributes.add(createAttribute(WSSConstants.ATT_WSSE11_TOKEN_TYPE, WSSConstants.NS_WSS_ENC_KEY_VALUE_TYPE));
440                     createStartElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_SECURITY_TOKEN_REFERENCE,
441                                                        false, attributes);
442                 } else {
443                     createStartElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_SECURITY_TOKEN_REFERENCE,
444                                                        true, null);
445                 }
446 
447                 if (isSAMLToken) {
448                     // Always use KeyIdentifier regardless of the configured KeyIdentifier value
449                     WSSUtils.createSAMLKeyIdentifierStructure(this, outputProcessorChain, securityToken.getTokenType(),
450                                                               getEncryptionPartDef().getKeyId());
451                 } else {
452                     List<XMLSecAttribute> attributes = new ArrayList<>(1);
453                     attributes.add(createAttribute(WSSConstants.ATT_NULL_URI, "#" + getEncryptionPartDef().getKeyId()));
454                     if (WSSecurityTokenConstants.KERBEROS_TOKEN.equals(securityToken.getTokenType())) {
455                         attributes.add(createAttribute(WSSConstants.ATT_NULL_VALUE_TYPE, WSSConstants.NS_GSS_KERBEROS5_AP_REQ));
456                     } else if (WSSecurityTokenConstants.DerivedKeyToken.equals(securityToken.getTokenType())) {
457                         boolean use200512Namespace = ((WSSSecurityProperties)getSecurityProperties()).isUse200512Namespace();
458                         if (use200512Namespace) {
459                             attributes.add(createAttribute(WSSConstants.ATT_NULL_VALUE_TYPE, WSSConstants.NS_WSC_05_12 + "/dk"));
460                         } else {
461                             attributes.add(createAttribute(WSSConstants.ATT_NULL_VALUE_TYPE, WSSConstants.NS_WSC_05_02 + "/dk"));
462                         }
463                     } else if (WSSecurityTokenConstants.SPNEGO_CONTEXT_TOKEN.equals(securityToken.getTokenType())
464                         || WSSecurityTokenConstants.SECURITY_CONTEXT_TOKEN.equals(securityToken.getTokenType())
465                         || WSSecurityTokenConstants.SECURE_CONVERSATION_TOKEN.equals(securityToken.getTokenType())) {
466                         boolean use200512Namespace = ((WSSSecurityProperties)getSecurityProperties()).isUse200512Namespace();
467                         if (use200512Namespace) {
468                             attributes.add(createAttribute(WSSConstants.ATT_NULL_VALUE_TYPE, WSSConstants.NS_WSC_05_12 + "/sct"));
469                         } else {
470                             attributes.add(createAttribute(WSSConstants.ATT_NULL_VALUE_TYPE, WSSConstants.NS_WSC_05_02 + "/sct"));
471                         }
472                     } else if (WSSecurityTokenConstants.EncryptedKeyToken.equals(securityToken.getTokenType())) {
473                         attributes.add(createAttribute(WSSConstants.ATT_NULL_VALUE_TYPE, WSSConstants.NS_WSS_ENC_KEY_VALUE_TYPE));
474                     }
475                     createStartElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_REFERENCE, false, attributes);
476                     createEndElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_REFERENCE);
477                 }
478             }
479             createEndElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_SECURITY_TOKEN_REFERENCE);
480             createEndElementAndOutputAsEvent(outputProcessorChain, XMLSecurityConstants.TAG_dsig_KeyInfo);
481         }
482 
483         @Override
484         protected void doFinalInternal(OutputProcessorChain outputProcessorChain) throws XMLStreamException, XMLSecurityException {
485 
486             super.doFinalInternal(outputProcessorChain);
487 
488             if (doEncryptedHeader) {
489                 createEndElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_wsse11_EncryptedHeader);
490             }
491         }
492     }
493 }