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.InvalidAlgorithmParameterException;
23  import java.security.InvalidKeyException;
24  import java.security.Key;
25  import java.security.NoSuchProviderException;
26  import java.security.Provider;
27  import java.security.PublicKey;
28  import java.security.cert.X509Certificate;
29  import java.security.spec.MGF1ParameterSpec;
30  
31  import javax.crypto.Cipher;
32  import javax.crypto.IllegalBlockSizeException;
33  import javax.crypto.SecretKey;
34  import javax.crypto.spec.OAEPParameterSpec;
35  import javax.crypto.spec.PSource;
36  import javax.xml.crypto.MarshalException;
37  import javax.xml.crypto.dom.DOMStructure;
38  import javax.xml.crypto.dsig.XMLSignatureFactory;
39  import javax.xml.crypto.dsig.keyinfo.KeyInfo;
40  import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
41  import javax.xml.crypto.dsig.keyinfo.KeyValue;
42  
43  import org.apache.wss4j.common.crypto.Crypto;
44  import org.apache.wss4j.common.crypto.CryptoType;
45  import org.apache.wss4j.common.ext.WSSecurityException;
46  import org.apache.wss4j.common.token.BinarySecurity;
47  import org.apache.wss4j.common.token.DOMX509Data;
48  import org.apache.wss4j.common.token.DOMX509IssuerSerial;
49  import org.apache.wss4j.common.token.Reference;
50  import org.apache.wss4j.common.token.SecurityTokenReference;
51  import org.apache.wss4j.common.token.X509Security;
52  import org.apache.wss4j.common.util.AttachmentUtils;
53  import org.apache.wss4j.common.util.KeyUtils;
54  import org.apache.wss4j.dom.WSConstants;
55  import org.apache.wss4j.dom.util.WSSecurityUtil;
56  import org.apache.xml.security.algorithms.JCEMapper;
57  import org.apache.xml.security.stax.impl.util.IDGenerator;
58  import org.apache.xml.security.utils.Constants;
59  import org.apache.xml.security.utils.XMLUtils;
60  import org.w3c.dom.Document;
61  import org.w3c.dom.Element;
62  import org.w3c.dom.Text;
63  
64  /**
65   * Builder class to build an EncryptedKey.
66   *
67   * This is especially useful in the case where the same
68   * <code>EncryptedKey</code> has to be used to sign and encrypt the message In
69   * such a situation this builder will add the <code>EncryptedKey</code> to the
70   * security header and we can use the information form the builder to provide to
71   * other builders to reference to the token
72   */
73  public class WSSecEncryptedKey extends WSSecBase {
74  
75      private static final org.slf4j.Logger LOG =
76          org.slf4j.LoggerFactory.getLogger(WSSecEncryptedKey.class);
77  
78      /**
79       * Algorithm used to encrypt the ephemeral key
80       */
81      private String keyEncAlgo = WSConstants.KEYTRANSPORT_RSAOAEP;
82  
83      /**
84       * Digest Algorithm to be used with RSA-OAEP. The default is SHA-1 (which is not
85       * written out unless it is explicitly configured).
86       */
87      private String digestAlgo;
88  
89      /**
90       * MGF Algorithm to be used with RSA-OAEP. The default is MGF-SHA-1 (which is not
91       * written out unless it is explicitly configured).
92       */
93      private String mgfAlgo;
94  
95      /**
96       * xenc:EncryptedKey element
97       */
98      private Element encryptedKeyElement;
99  
100     /**
101      * The Token identifier of the token that the <code>DerivedKeyToken</code>
102      * is (or to be) derived from.
103      */
104     private String encKeyId;
105 
106     /**
107      * BinarySecurityToken to be included in the case where BST_DIRECT_REFERENCE
108      * is used to refer to the asymmetric encryption cert
109      */
110     private BinarySecurity bstToken;
111 
112     private X509Certificate useThisCert;
113 
114     private PublicKey useThisPublicKey;
115 
116     /**
117      * Custom token value
118      */
119     private String customEKTokenValueType;
120 
121     /**
122      * Custom token id
123      */
124     private String customEKTokenId;
125 
126     private boolean bstAddedToSecurityHeader;
127     private boolean includeEncryptionToken;
128     private Element customEKKeyInfoElement;
129     private Provider provider;
130 
131     private String encryptedKeySHA1;
132 
133     public WSSecEncryptedKey(WSSecHeader securityHeader) {
134         super(securityHeader);
135     }
136 
137     public WSSecEncryptedKey(Document doc) {
138         this(doc, null);
139     }
140 
141     public WSSecEncryptedKey(Document doc, Provider provider) {
142         super(doc);
143         this.provider = provider;
144     }
145 
146     /**
147      * Set the user name to get the encryption certificate.
148      *
149      * The public key of this certificate is used, thus no password necessary.
150      * The user name is a keystore alias usually.
151      *
152      * @param user
153      */
154     public void setUserInfo(String user) {
155         this.user = user;
156     }
157 
158     /**
159      * Get the id generated during <code>prepare()</code>.
160      *
161      * Returns the the value of wsu:Id attribute of the EncryptedKey element.
162      *
163      * @return Return the wsu:Id of this token or null if <code>prepare()</code>
164      *         was not called before.
165      */
166     public String getId() {
167         return encKeyId;
168     }
169 
170     /**
171      * Create the EncryptedKey Element for inclusion in the security header, by encrypting the
172      * symmetricKey parameter using either a public key or certificate that is set on the class,
173      * and adding the encrypted bytes as the CipherValue of the EncryptedKey element. The KeyInfo
174      * is constructed according to the keyIdentifierType and also the type of the encrypting
175      * key
176      *
177      * @param crypto An instance of the Crypto API to handle keystore and certificates
178      * @param symmetricKey The symmetric key to encrypt and insert into the EncryptedKey
179      * @throws WSSecurityException
180      */
181     public void prepare(Crypto crypto, SecretKey symmetricKey) throws WSSecurityException {
182 
183         if (useThisPublicKey != null) {
184             createEncryptedKeyElement(useThisPublicKey);
185             byte[] encryptedEphemeralKey = encryptSymmetricKey(useThisPublicKey, symmetricKey);
186             addCipherValueElement(encryptedEphemeralKey);
187         } else {
188             //
189             // Get the certificate that contains the public key for the public key
190             // algorithm that will encrypt the generated symmetric (session) key.
191             //
192             X509Certificate remoteCert = useThisCert;
193             if (remoteCert == null) {
194                 CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
195                 cryptoType.setAlias(user);
196                 if (crypto == null) {
197                     throw new WSSecurityException(
198                                                   WSSecurityException.ErrorCode.FAILURE,
199                                                   "noUserCertsFound",
200                                                   new Object[] {user, "encryption"});
201                 }
202                 X509Certificate[] certs = crypto.getX509Certificates(cryptoType);
203                 if (certs == null || certs.length <= 0) {
204                     throw new WSSecurityException(
205                                                   WSSecurityException.ErrorCode.FAILURE,
206                                                   "noUserCertsFound",
207                                                   new Object[] {user, "encryption"});
208                 }
209                 remoteCert = certs[0];
210             }
211 
212             createEncryptedKeyElement(remoteCert, crypto);
213             byte[] encryptedEphemeralKey = encryptSymmetricKey(remoteCert.getPublicKey(), symmetricKey);
214             addCipherValueElement(encryptedEphemeralKey);
215         }
216     }
217 
218     /**
219      * Create and add the CipherValue Element to the EncryptedKey Element.
220      */
221     protected void addCipherValueElement(byte[] encryptedEphemeralKey) throws WSSecurityException {
222         Element xencCipherValue = createCipherValue(getDocument(), encryptedKeyElement);
223         if (storeBytesInAttachment) {
224             final String attachmentId = getIdAllocator().createId("", getDocument());
225             AttachmentUtils.storeBytesInAttachment(xencCipherValue, getDocument(), attachmentId,
226                                                   encryptedEphemeralKey, attachmentCallbackHandler);
227         } else {
228             Text keyText =
229                 WSSecurityUtil.createBase64EncodedTextNode(getDocument(), encryptedEphemeralKey);
230             xencCipherValue.appendChild(keyText);
231         }
232 
233         setEncryptedKeySHA1(encryptedEphemeralKey);
234     }
235 
236     /**
237      * Now we need to setup the EncryptedKey header block:
238      *  1) create a EncryptedKey element and set a wsu:Id for it
239      *  2) Generate ds:KeyInfo element, this wraps the wsse:SecurityTokenReference
240      *  3) Create and set up the SecurityTokenReference according to the keyIdentifier parameter
241      *  4) Create the CipherValue element structure and insert the encrypted session key
242      */
243     protected void createEncryptedKeyElement(X509Certificate remoteCert, Crypto crypto) throws WSSecurityException {
244         encryptedKeyElement = createEncryptedKey(getDocument(), keyEncAlgo);
245         if (encKeyId == null || encKeyId.length() == 0) {
246             encKeyId = IDGenerator.generateID("EK-");
247         }
248         encryptedKeyElement.setAttributeNS(null, "Id", encKeyId);
249 
250         if (customEKKeyInfoElement != null) {
251             encryptedKeyElement.appendChild(getDocument().adoptNode(customEKKeyInfoElement));
252         } else {
253             SecurityTokenReference secToken = new SecurityTokenReference(getDocument());
254             if (addWSUNamespace) {
255                 secToken.addWSUNamespace();
256             }
257 
258             switch (keyIdentifierType) {
259             case WSConstants.X509_KEY_IDENTIFIER:
260                 secToken.setKeyIdentifier(remoteCert);
261                 break;
262 
263             case WSConstants.SKI_KEY_IDENTIFIER:
264                 secToken.setKeyIdentifierSKI(remoteCert, crypto);
265 
266                 if (includeEncryptionToken) {
267                     addBST(remoteCert);
268                 }
269                 break;
270 
271             case WSConstants.THUMBPRINT_IDENTIFIER:
272             case WSConstants.ENCRYPTED_KEY_SHA1_IDENTIFIER:
273                 //
274                 // This identifier is not applicable for this case, so fall back to
275                 // ThumbprintRSA.
276                 //
277                 secToken.setKeyIdentifierThumb(remoteCert);
278 
279                 if (includeEncryptionToken) {
280                     addBST(remoteCert);
281                 }
282                 break;
283 
284             case WSConstants.ISSUER_SERIAL:
285                 addIssuerSerial(remoteCert, secToken, false);
286                 break;
287 
288             case WSConstants.ISSUER_SERIAL_QUOTE_FORMAT:
289                 addIssuerSerial(remoteCert, secToken,true);
290                 break;
291 
292             case WSConstants.BST_DIRECT_REFERENCE:
293                 Reference ref = new Reference(getDocument());
294                 String certUri = IDGenerator.generateID(null);
295                 ref.setURI("#" + certUri);
296                 bstToken = new X509Security(getDocument());
297                 ((X509Security) bstToken).setX509Certificate(remoteCert);
298                 bstToken.setID(certUri);
299                 ref.setValueType(bstToken.getValueType());
300                 secToken.setReference(ref);
301                 break;
302 
303             case WSConstants.CUSTOM_SYMM_SIGNING :
304                 Reference refCust = new Reference(getDocument());
305                 if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
306                     secToken.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
307                     refCust.setValueType(customEKTokenValueType);
308                 } else if (WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
309                     secToken.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
310                 } else if (WSConstants.WSS_ENC_KEY_VALUE_TYPE.equals(customEKTokenValueType)) {
311                     secToken.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
312                     refCust.setValueType(customEKTokenValueType);
313                 } else {
314                     refCust.setValueType(customEKTokenValueType);
315                 }
316                 refCust.setURI("#" + customEKTokenId);
317                 secToken.setReference(refCust);
318                 break;
319 
320             case WSConstants.CUSTOM_SYMM_SIGNING_DIRECT :
321                 Reference refCustd = new Reference(getDocument());
322                 if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
323                     secToken.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
324                     refCustd.setValueType(customEKTokenValueType);
325                 } else if (WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
326                     secToken.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
327                 }  else if (WSConstants.WSS_ENC_KEY_VALUE_TYPE.equals(customEKTokenValueType)) {
328                     secToken.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
329                     refCustd.setValueType(customEKTokenValueType);
330                 } else {
331                     refCustd.setValueType(customEKTokenValueType);
332                 }
333                 refCustd.setURI(customEKTokenId);
334                 secToken.setReference(refCustd);
335                 break;
336 
337             case WSConstants.CUSTOM_KEY_IDENTIFIER:
338                 secToken.setKeyIdentifier(customEKTokenValueType, customEKTokenId);
339                 if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
340                     secToken.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
341                 } else if (WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
342                     secToken.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
343                 } else if (WSConstants.WSS_ENC_KEY_VALUE_TYPE.equals(customEKTokenValueType)) {
344                     secToken.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
345                 } else if (SecurityTokenReference.ENC_KEY_SHA1_URI.equals(customEKTokenValueType)) {
346                     secToken.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
347                 }
348                 break;
349 
350             default:
351                 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "unsupportedKeyId",
352                                               new Object[] {keyIdentifierType});
353             }
354             Element keyInfoElement =
355                 getDocument().createElementNS(
356                     WSConstants.SIG_NS, WSConstants.SIG_PREFIX + ":" + WSConstants.KEYINFO_LN
357                 );
358             keyInfoElement.setAttributeNS(
359                 WSConstants.XMLNS_NS, "xmlns:" + WSConstants.SIG_PREFIX, WSConstants.SIG_NS
360             );
361             keyInfoElement.appendChild(secToken.getElement());
362             encryptedKeyElement.appendChild(keyInfoElement);
363         }
364 
365     }
366 
367     private void addIssuerSerial(X509Certificate remoteCert, SecurityTokenReference secToken, boolean isCommaDelimited)
368             throws WSSecurityException {
369         String issuer = remoteCert.getIssuerX500Principal().getName();
370         java.math.BigInteger serialNumber = remoteCert.getSerialNumber();
371         DOMX509IssuerSerial domIssuerSerial =
372                 new DOMX509IssuerSerial(getDocument(), issuer, serialNumber, isCommaDelimited);
373         DOMX509Data domX509Data = new DOMX509Data(getDocument(), domIssuerSerial);
374         secToken.setUnknownElement(domX509Data.getElement());
375 
376         if (includeEncryptionToken) {
377             addBST(remoteCert);
378         }
379     }
380 
381     /**
382      * Now we need to setup the EncryptedKey header block:
383      *  1) create a EncryptedKey element and set a wsu:Id for it
384      *  2) Generate ds:KeyInfo element, this wraps the wsse:SecurityTokenReference
385      *  3) Create and set up the SecurityTokenReference according to the keyIdentifier parameter
386      *  4) Create the CipherValue element structure and insert the encrypted session key
387      */
388     protected void createEncryptedKeyElement(Key key) throws WSSecurityException {
389         encryptedKeyElement = createEncryptedKey(getDocument(), keyEncAlgo);
390         if (encKeyId == null || encKeyId.length() == 0) {
391             encKeyId = IDGenerator.generateID("EK-");
392         }
393         encryptedKeyElement.setAttributeNS(null, "Id", encKeyId);
394 
395         if (customEKKeyInfoElement != null) {
396             encryptedKeyElement.appendChild(getDocument().adoptNode(customEKKeyInfoElement));
397         } else {
398             SecurityTokenReference secToken = new SecurityTokenReference(getDocument());
399             if (addWSUNamespace) {
400                 secToken.addWSUNamespace();
401             }
402 
403             switch (keyIdentifierType) {
404 
405                 case WSConstants.CUSTOM_SYMM_SIGNING :
406                     Reference refCust = new Reference(getDocument());
407                     if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
408                         secToken.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
409                         refCust.setValueType(customEKTokenValueType);
410                     } else if (WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
411                         secToken.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
412                     } else if (WSConstants.WSS_ENC_KEY_VALUE_TYPE.equals(customEKTokenValueType)) {
413                         secToken.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
414                         refCust.setValueType(customEKTokenValueType);
415                     } else {
416                         refCust.setValueType(customEKTokenValueType);
417                     }
418                     refCust.setURI("#" + customEKTokenId);
419                     secToken.setReference(refCust);
420                     break;
421 
422                 case WSConstants.CUSTOM_SYMM_SIGNING_DIRECT :
423                     Reference refCustd = new Reference(getDocument());
424                     if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
425                         secToken.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
426                         refCustd.setValueType(customEKTokenValueType);
427                     } else if (WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
428                         secToken.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
429                     }  else if (WSConstants.WSS_ENC_KEY_VALUE_TYPE.equals(customEKTokenValueType)) {
430                         secToken.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
431                         refCustd.setValueType(customEKTokenValueType);
432                     } else {
433                         refCustd.setValueType(customEKTokenValueType);
434                     }
435                     refCustd.setURI(customEKTokenId);
436                     secToken.setReference(refCustd);
437                     break;
438 
439                 case WSConstants.CUSTOM_KEY_IDENTIFIER:
440                     secToken.setKeyIdentifier(customEKTokenValueType, customEKTokenId);
441                     if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
442                         secToken.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
443                     } else if (WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
444                         secToken.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
445                     } else if (WSConstants.WSS_ENC_KEY_VALUE_TYPE.equals(customEKTokenValueType)) {
446                         secToken.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
447                     } else if (SecurityTokenReference.ENC_KEY_SHA1_URI.equals(customEKTokenValueType)) {
448                         secToken.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
449                     }
450                     break;
451 
452                 case WSConstants.KEY_VALUE:
453                     // This is only applicable for the PublicKey case
454                     if (!(key instanceof PublicKey)) {
455                         throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "unsupportedKeyId",
456                                                       new Object[] {keyIdentifierType});
457                     }
458                     try {
459                         XMLSignatureFactory signatureFactory;
460                         if (provider == null) {
461                             // Try to install the Santuario Provider - fall back to the JDK provider if this does
462                             // not work
463                             try {
464                                 signatureFactory = XMLSignatureFactory.getInstance("DOM", "ApacheXMLDSig");
465                             } catch (NoSuchProviderException ex) {
466                                 signatureFactory = XMLSignatureFactory.getInstance("DOM");
467                             }
468                         } else {
469                             signatureFactory = XMLSignatureFactory.getInstance("DOM", provider);
470                         }
471 
472                         KeyInfoFactory keyInfoFactory = signatureFactory.getKeyInfoFactory();
473                         KeyValue keyValue = keyInfoFactory.newKeyValue((PublicKey)key);
474                         String keyInfoUri = getIdAllocator().createSecureId("KI-", null);
475                         KeyInfo keyInfo =
476                             keyInfoFactory.newKeyInfo(
477                                 java.util.Collections.singletonList(keyValue), keyInfoUri
478                             );
479 
480                         keyInfo.marshal(new DOMStructure(encryptedKeyElement), null);
481                     } catch (java.security.KeyException | MarshalException ex) {
482                         LOG.error("", ex);
483                         throw new WSSecurityException(
484                             WSSecurityException.ErrorCode.FAILED_ENCRYPTION, ex
485                         );
486                     }
487                     break;
488 
489                 default:
490                     throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "unsupportedKeyId",
491                                                   new Object[] {keyIdentifierType});
492             }
493 
494             if (WSConstants.KEY_VALUE != keyIdentifierType) {
495                 Element keyInfoElement =
496                     getDocument().createElementNS(
497                         WSConstants.SIG_NS, WSConstants.SIG_PREFIX + ":" + WSConstants.KEYINFO_LN
498                     );
499                 keyInfoElement.setAttributeNS(
500                     WSConstants.XMLNS_NS, "xmlns:" + WSConstants.SIG_PREFIX, WSConstants.SIG_NS
501                 );
502                 keyInfoElement.appendChild(secToken.getElement());
503                 encryptedKeyElement.appendChild(keyInfoElement);
504             }
505         }
506     }
507 
508     protected byte[] encryptSymmetricKey(PublicKey encryptingKey, SecretKey keyToBeEncrypted)
509         throws WSSecurityException {
510         Cipher cipher = KeyUtils.getCipherInstance(keyEncAlgo);
511         try {
512             OAEPParameterSpec oaepParameterSpec = null;
513             if (WSConstants.KEYTRANSPORT_RSAOAEP.equals(keyEncAlgo)
514                     || WSConstants.KEYTRANSPORT_RSAOAEP_XENC11.equals(keyEncAlgo)) {
515                 String jceDigestAlgorithm = "SHA-1";
516                 if (digestAlgo != null) {
517                     jceDigestAlgorithm = JCEMapper.translateURItoJCEID(digestAlgo);
518                 }
519 
520                 MGF1ParameterSpec mgf1ParameterSpec = new MGF1ParameterSpec("SHA-1");
521                 if (WSConstants.KEYTRANSPORT_RSAOAEP_XENC11.equals(keyEncAlgo)) {
522                     if (WSConstants.MGF_SHA224.equals(mgfAlgo)) {
523                         mgf1ParameterSpec = new MGF1ParameterSpec("SHA-224");
524                     } else if (WSConstants.MGF_SHA256.equals(mgfAlgo)) {
525                         mgf1ParameterSpec = new MGF1ParameterSpec("SHA-256");
526                     } else if (WSConstants.MGF_SHA384.equals(mgfAlgo)) {
527                         mgf1ParameterSpec = new MGF1ParameterSpec("SHA-384");
528                     } else if (WSConstants.MGF_SHA512.equals(mgfAlgo)) {
529                         mgf1ParameterSpec = new MGF1ParameterSpec("SHA-512");
530                     }
531                 }
532 
533                 oaepParameterSpec =
534                     new OAEPParameterSpec(
535                         jceDigestAlgorithm, "MGF1", mgf1ParameterSpec, PSource.PSpecified.DEFAULT
536                     );
537             }
538             if (oaepParameterSpec == null) {
539                 cipher.init(Cipher.WRAP_MODE, encryptingKey);
540             } else {
541                 cipher.init(Cipher.WRAP_MODE, encryptingKey, oaepParameterSpec);
542             }
543         } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
544             throw new WSSecurityException(
545                 WSSecurityException.ErrorCode.FAILED_ENCRYPTION, e
546             );
547         }
548         int blockSize = cipher.getBlockSize();
549         LOG.debug("cipher blksize: {}", blockSize);
550 
551         try {
552             return cipher.wrap(keyToBeEncrypted);
553         } catch (IllegalStateException | IllegalBlockSizeException | InvalidKeyException ex) {
554             throw new WSSecurityException(
555                 WSSecurityException.ErrorCode.FAILED_ENCRYPTION, ex
556             );
557         }
558     }
559 
560     /**
561      * Add a BinarySecurityToken
562      */
563     private void addBST(X509Certificate cert) throws WSSecurityException {
564         bstToken = new X509Security(getDocument());
565         ((X509Security) bstToken).setX509Certificate(cert);
566 
567         bstAddedToSecurityHeader = false;
568         bstToken.setID(IDGenerator.generateID(null));
569         if (addWSUNamespace) {
570             bstToken.addWSUNamespace();
571         }
572     }
573 
574     /**
575      * Create DOM subtree for <code>xenc:EncryptedKey</code>
576      *
577      * @param doc the SOAP envelope parent document
578      * @param keyTransportAlgo specifies which algorithm to use to encrypt the symmetric key
579      * @return an <code>xenc:EncryptedKey</code> element
580      */
581     private Element createEncryptedKey(Document doc, String keyTransportAlgo) {
582         Element encryptedKey =
583             doc.createElementNS(WSConstants.ENC_NS, WSConstants.ENC_PREFIX + ":EncryptedKey");
584 
585         org.apache.wss4j.common.util.XMLUtils.setNamespace(encryptedKey, WSConstants.ENC_NS, WSConstants.ENC_PREFIX);
586         Element encryptionMethod =
587             doc.createElementNS(WSConstants.ENC_NS, WSConstants.ENC_PREFIX + ":EncryptionMethod");
588         encryptionMethod.setAttributeNS(null, "Algorithm", keyTransportAlgo);
589 
590         if (digestAlgo != null) {
591             Element digestElement =
592                 XMLUtils.createElementInSignatureSpace(doc, Constants._TAG_DIGESTMETHOD);
593             digestElement.setAttributeNS(null, "Algorithm", digestAlgo);
594             encryptionMethod.appendChild(digestElement);
595         }
596         if (WSConstants.KEYTRANSPORT_RSAOAEP_XENC11.equals(keyEncAlgo) && mgfAlgo != null) {
597             Element mgfElement =
598                 doc.createElementNS(WSConstants.ENC11_NS, WSConstants.ENC11_PREFIX + ":MGF");
599             mgfElement.setAttributeNS(null, "Algorithm", mgfAlgo);
600             encryptionMethod.appendChild(mgfElement);
601         }
602 
603         encryptedKey.appendChild(encryptionMethod);
604         return encryptedKey;
605     }
606 
607     protected Element createCipherValue(Document doc, Element encryptedKey) {
608         Element cipherData =
609             doc.createElementNS(WSConstants.ENC_NS, WSConstants.ENC_PREFIX + ":CipherData");
610         Element cipherValue =
611             doc.createElementNS(WSConstants.ENC_NS, WSConstants.ENC_PREFIX + ":CipherValue");
612         cipherData.appendChild(cipherValue);
613         encryptedKey.appendChild(cipherData);
614         return cipherValue;
615     }
616 
617     /**
618      * Prepend the EncryptedKey element to the elements already in the Security
619      * header.
620      *
621      * The method can be called any time after <code>prepare()</code>. This
622      * allows to insert the EncryptedKey element at any position in the Security
623      * header.
624      */
625     public void prependToHeader() {
626         Element secHeaderElement = getSecurityHeader().getSecurityHeaderElement();
627         WSSecurityUtil.prependChildElement(secHeaderElement, encryptedKeyElement);
628     }
629 
630     /**
631      * Append the EncryptedKey element to the elements already in the Security
632      * header.
633      *
634      * The method can be called any time after <code>prepare()</code>. This
635      * allows to insert the EncryptedKey element at any position in the Security
636      * header.
637      */
638     public void appendToHeader() {
639         Element secHeaderElement = getSecurityHeader().getSecurityHeaderElement();
640         secHeaderElement.appendChild(encryptedKeyElement);
641     }
642 
643     /**
644      * Prepend the BinarySecurityToken to the elements already in the Security
645      * header.
646      *
647      * The method can be called any time after <code>prepare()</code>. This
648      * allows to insert the BST element at any position in the Security header.
649      */
650     public void prependBSTElementToHeader() {
651         if (bstToken != null && !bstAddedToSecurityHeader) {
652             Element secHeaderElement = getSecurityHeader().getSecurityHeaderElement();
653             WSSecurityUtil.prependChildElement(secHeaderElement, bstToken.getElement());
654             bstAddedToSecurityHeader = true;
655         }
656     }
657 
658     /**
659      * Append the BinarySecurityToken to the elements already in the Security
660      * header.
661      *
662      * The method can be called any time after <code>prepare()</code>. This
663      * allows to insert the BST element at any position in the Security header.
664      */
665     public void appendBSTElementToHeader() {
666         if (bstToken != null && !bstAddedToSecurityHeader) {
667             Element secHeaderElement = getSecurityHeader().getSecurityHeaderElement();
668             secHeaderElement.appendChild(bstToken.getElement());
669             bstAddedToSecurityHeader = true;
670         }
671     }
672 
673     /**
674      * Set the X509 Certificate to use for encryption.
675      *
676      * If this is set <b>and</b> the key identifier is set to
677      * <code>DirectReference</code> then use this certificate to get the
678      * public key for encryption.
679      *
680      * @param cert is the X509 certificate to use for encryption
681      */
682     public void setUseThisCert(X509Certificate cert) {
683         useThisCert = cert;
684     }
685 
686     public X509Certificate getUseThisCert() {
687         return useThisCert;
688     }
689 
690     /**
691      * Set the PublicKey to use for encryption.
692      * @param key the PublicKey instance to use for encryption
693      */
694     public void setUseThisPublicKey(PublicKey key) {
695         useThisPublicKey = key;
696     }
697 
698     public PublicKey getUseThisPublicKey() {
699         return useThisPublicKey;
700     }
701 
702     /**
703      * @return Returns the encryptedKeyElement.
704      */
705     public Element getEncryptedKeyElement() {
706         return encryptedKeyElement;
707     }
708 
709     /**
710      * Set the encrypted key element when a pre prepared encrypted key is used
711      * @param encryptedKeyElement EncryptedKey element of the encrypted key used
712      */
713     public void setEncryptedKeyElement(Element encryptedKeyElement) {
714         this.encryptedKeyElement = encryptedKeyElement;
715     }
716 
717     /**
718      * @return Returns the BinarySecurityToken element.
719      */
720     public Element getBinarySecurityTokenElement() {
721         if (bstToken != null) {
722             return bstToken.getElement();
723         }
724         return null;
725     }
726 
727     public void setKeyEncAlgo(String keyEncAlgo) {
728         this.keyEncAlgo = keyEncAlgo;
729     }
730 
731     public String getKeyEncAlgo() {
732         return keyEncAlgo;
733     }
734 
735     /**
736      * Get the id of the BSt generated  during <code>prepare()</code>.
737      *
738      * @return Returns the the value of wsu:Id attribute of the
739      * BinaruSecurityToken element.
740      */
741     public String getBSTTokenId() {
742         if (bstToken == null) {
743             return null;
744         }
745 
746         return bstToken.getID();
747     }
748 
749     /**
750      * @param encKeyId The encKeyId to set.
751      */
752     public void setEncKeyId(String encKeyId) {
753         this.encKeyId = encKeyId;
754     }
755 
756     public boolean isCertSet() {
757         return useThisCert != null;
758     }
759 
760     public void setCustomEKTokenValueType(String customEKTokenValueType) {
761         this.customEKTokenValueType = customEKTokenValueType;
762     }
763 
764     public void setCustomEKTokenId(String customEKTokenId) {
765         this.customEKTokenId = customEKTokenId;
766     }
767 
768     /**
769      * Set the digest algorithm to use with the RSA-OAEP key transport algorithm. The
770      * default is SHA-1.
771      *
772      * @param digestAlgorithm the digest algorithm to use with the RSA-OAEP key transport algorithm
773      */
774     public void setDigestAlgorithm(String digestAlgorithm) {
775         this.digestAlgo = digestAlgorithm;
776     }
777 
778     /**
779      * Get the digest algorithm to use with the RSA-OAEP key transport algorithm. The
780      * default is SHA-1.
781      */
782     public String getDigestAlgorithm() {
783         return digestAlgo;
784     }
785 
786     /**
787      * Set the MGF algorithm to use with the RSA-OAEP key transport algorithm. The
788      * default is MGF-SHA-1.
789      *
790      * @param mgfAlgorithm the MGF algorithm to use with the RSA-OAEP key transport algorithm
791      */
792     public void setMGFAlgorithm(String mgfAlgorithm) {
793         this.mgfAlgo = mgfAlgorithm;
794     }
795 
796     /**
797      * Get the MGF algorithm to use with the RSA-OAEP key transport algorithm. The
798      * default is MGF-SHA-1.
799      */
800     public String getMGFAlgorithm() {
801         return mgfAlgo;
802     }
803 
804     public boolean isIncludeEncryptionToken() {
805         return includeEncryptionToken;
806     }
807 
808     public void setIncludeEncryptionToken(boolean includeEncryptionToken) {
809         this.includeEncryptionToken = includeEncryptionToken;
810     }
811 
812     public Element getCustomEKKeyInfoElement() {
813         return customEKKeyInfoElement;
814     }
815 
816     public void setCustomEKKeyInfoElement(Element customEKKeyInfoElement) {
817         this.customEKKeyInfoElement = customEKKeyInfoElement;
818     }
819 
820     protected void setEncryptedKeySHA1(byte[] encryptedEphemeralKey) throws WSSecurityException {
821         byte[] encodedBytes = KeyUtils.generateDigest(encryptedEphemeralKey);
822         encryptedKeySHA1 = XMLUtils.encodeToString(encodedBytes);
823     }
824 
825     public String getEncryptedKeySHA1() {
826         return encryptedKeySHA1;
827     }
828 }