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.ws.security.message;
21  
22  import org.apache.ws.security.WSConstants;
23  import org.apache.ws.security.WSEncryptionPart;
24  import org.apache.ws.security.WSSConfig;
25  import org.apache.ws.security.WSSecurityException;
26  import org.apache.ws.security.conversation.ConversationException;
27  import org.apache.ws.security.message.token.Reference;
28  import org.apache.ws.security.message.token.SecurityTokenReference;
29  import org.apache.ws.security.util.WSSecurityUtil;
30  import org.apache.xml.security.keys.KeyInfo;
31  import org.w3c.dom.Document;
32  import org.w3c.dom.Element;
33  import org.w3c.dom.Node;
34  
35  import javax.crypto.SecretKey;
36  
37  import java.util.ArrayList;
38  import java.util.List;
39  
40  /**
41   * Encrypts and signs parts of a message with derived keys derived from a
42   * symmetric key. This symmetric key will be included as an EncryptedKey
43   * 
44   * @author Ruchith Fernando (ruchith.fernando@gmail.com)
45   */
46  public class WSSecDKEncrypt extends WSSecDerivedKeyBase {
47  
48      protected String symEncAlgo = WSConstants.AES_128;
49      
50      public WSSecDKEncrypt() {
51          super();
52      }
53      public WSSecDKEncrypt(WSSConfig config) {
54          super(config);
55      }
56      
57      public Document build(Document doc, WSSecHeader secHeader)
58          throws WSSecurityException, ConversationException {
59          
60          //
61          // Setup the encrypted key
62          //
63          prepare(doc);
64          envelope = doc.getDocumentElement();
65          //
66          // prepend elements in the right order to the security header
67          //
68          prependDKElementToHeader(secHeader);
69                  
70          String soapNamespace = WSSecurityUtil.getSOAPNamespace(envelope);
71          if (parts == null) {
72              parts = new ArrayList<WSEncryptionPart>(1);
73              WSEncryptionPart encP = 
74                  new WSEncryptionPart(
75                      WSConstants.ELEM_BODY, 
76                      soapNamespace, 
77                      "Content"
78                  );
79              parts.add(encP);
80          }
81          Element externRefList = encryptForExternalRef(null, parts);
82          addExternalRefElement(externRefList, secHeader);
83  
84          return doc;
85      }
86  
87      /**
88       * Encrypt one or more parts or elements of the message (external).
89       * 
90       * This method takes a vector of <code>WSEncryptionPart</code> object that
91       * contain information about the elements to encrypt. The method call the
92       * encryption method, takes the reference information generated during
93       * encryption and add this to the <code>xenc:Reference</code> element.
94       * This method can be called after <code>prepare()</code> and can be
95       * called multiple times to encrypt a number of parts or elements.
96       * 
97       * The method generates a <code>xenc:Reference</code> element that <i>must</i>
98       * be added to the SecurityHeader. See <code>addExternalRefElement()</code>.
99       * 
100      * If the <code>dataRef</code> parameter is <code>null</code> the method
101      * creates and initializes a new Reference element.
102      * 
103      * @param dataRef A <code>xenc:Reference</code> element or <code>null</code>
104      * @param references A list containing WSEncryptionPart objects
105      * @return Returns the updated <code>xenc:Reference</code> element
106      * @throws WSSecurityException
107      */
108     public Element encryptForExternalRef(Element dataRef, List<WSEncryptionPart> references)
109         throws WSSecurityException {
110         
111         KeyInfo keyInfo = createKeyInfo();
112         SecretKey key = WSSecurityUtil.prepareSecretKey(symEncAlgo, derivedKeyBytes);
113 
114         List<String> encDataRefs = 
115             WSSecEncrypt.doEncryption(
116                 document, getWsConfig(), keyInfo, key, symEncAlgo, references, callbackLookup
117             );
118         if (dataRef == null) {
119             dataRef = 
120                 document.createElementNS(
121                     WSConstants.ENC_NS, WSConstants.ENC_PREFIX + ":ReferenceList"
122                 );
123         }
124         return WSSecEncrypt.createDataRefList(document, dataRef, encDataRefs);
125     }
126     
127     /**
128      * Create a KeyInfo object
129      */
130     private KeyInfo createKeyInfo() throws WSSecurityException {
131         KeyInfo keyInfo = new KeyInfo(document);
132         SecurityTokenReference secToken = new SecurityTokenReference(document);
133         secToken.addWSSENamespace();
134         Reference ref = new Reference(document);
135         ref.setURI("#" + dktId);
136         secToken.setReference(ref);
137 
138         keyInfo.addUnknownElement(secToken.getElement());
139         Element keyInfoElement = keyInfo.getElement();
140         keyInfoElement.setAttributeNS(
141             WSConstants.XMLNS_NS, "xmlns:" + WSConstants.SIG_PREFIX, WSConstants.SIG_NS
142         );
143         
144         return keyInfo;
145     }
146     
147     /**
148      * Adds (prepends) the external Reference element to the Security header.
149      * 
150      * The reference element <i>must</i> be created by the
151      * <code>encryptForExternalRef() </code> method. The method adds the
152      * reference element in the SecurityHeader.
153      * 
154      * @param referenceList The external <code>enc:Reference</code> element
155      * @param secHeader The security header.
156      */
157     public void addExternalRefElement(Element referenceList, WSSecHeader secHeader) {
158         Node node = dkt.getElement().getNextSibling();
159         if (node != null && Node.ELEMENT_NODE == node.getNodeType()) {
160             secHeader.getSecurityHeader().insertBefore(referenceList, node);
161         } else {
162             // If (at this moment) DerivedKeyToken is the LAST element of 
163             // the security header 
164             secHeader.getSecurityHeader().appendChild(referenceList);
165         }
166     }
167 
168 
169     /**
170      * Set the symmetric encryption algorithm URI to use
171      * @param algo the symmetric encryption algorithm URI to use
172      */
173     public void setSymmetricEncAlgorithm(String algo) {
174         symEncAlgo = algo;
175     }
176 
177     /**
178      * @see org.apache.ws.security.message.WSSecDerivedKeyBase#getDerivedKeyLength()
179      */
180     protected int getDerivedKeyLength() throws WSSecurityException{
181         return (derivedKeyLength > 0) ? derivedKeyLength : 
182             WSSecurityUtil.getKeyLength(symEncAlgo);
183     }
184     
185 }