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.WSSConfig;
24  import org.apache.ws.security.WSSecurityException;
25  import org.apache.ws.security.conversation.ConversationConstants;
26  import org.apache.ws.security.conversation.ConversationException;
27  import org.apache.ws.security.conversation.dkalgo.AlgoFactory;
28  import org.apache.ws.security.conversation.dkalgo.DerivationAlgorithm;
29  import org.apache.ws.security.message.token.DerivedKeyToken;
30  import org.apache.ws.security.message.token.KerberosSecurity;
31  import org.apache.ws.security.message.token.Reference;
32  import org.apache.ws.security.message.token.SecurityTokenReference;
33  import org.apache.ws.security.util.Base64;
34  import org.apache.ws.security.util.WSSecurityUtil;
35  import org.w3c.dom.Document;
36  import org.w3c.dom.Element;
37  
38  import java.io.UnsupportedEncodingException;
39  
40  /**
41   * Base class for DerivedKey encryption and signature
42   *
43   * @author Ruchith Fernando (ruchith.fernando@gmail.com)
44   * @author Davanum Srinivas (dims@yahoo.com)
45   * @author Werner Dittmann (werner@apache.org)
46   */
47  public abstract class WSSecDerivedKeyBase extends WSSecSignatureBase {
48      
49      protected Document document;
50      
51      /**
52       * Session key used as the secret in key derivation
53       */
54      protected byte[] ephemeralKey;
55       
56      /**
57       * DerivedKeyToken of this builder
58       */
59      protected DerivedKeyToken dkt = null;
60      
61      /**
62       * Raw bytes of the derived key
63       */
64      protected byte[] derivedKeyBytes = null; 
65      
66      /**
67       * wsu:Id of the wsc:DerivedKeyToken
68       */
69      protected String dktId = null;
70      
71      /**
72       * Client's label value
73       */
74      protected String clientLabel = ConversationConstants.DEFAULT_LABEL;
75      
76      /**
77       * Service's label value
78       */
79      protected String serviceLabel = ConversationConstants.DEFAULT_LABEL;
80      
81      /**
82       * soap:Envelope element
83       */
84      protected Element envelope = null;
85      
86      /**
87       * The Token identifier of the token that the <code>DerivedKeyToken</code> 
88       * is (or to be) derived from.
89       */
90      protected String tokenIdentifier = null;
91      
92      /**
93       * True if the tokenIdentifier is a direct reference to a key identifier
94       * instead of a URI to a key
95       */
96      protected boolean tokenIdDirectId;
97  
98      /**
99       * The derived key will change depending on the sig/encr algorithm.
100      * Therefore the child classes are expected to provide this value.
101      * @return the derived key length
102      * @throws WSSecurityException
103      */
104     protected abstract int getDerivedKeyLength() throws WSSecurityException;
105    
106     /**
107      * The wsse:SecurityTokenReference element to be used
108      */
109     protected Element strElem;
110     
111     private int wscVersion = ConversationConstants.DEFAULT_VERSION;
112     
113     protected int derivedKeyLength = -1;
114     
115     private String customValueType;
116     
117     
118     public WSSecDerivedKeyBase() {
119         super();
120     }
121     public WSSecDerivedKeyBase(WSSConfig config) {
122         super(config);
123     }
124 
125     
126     /**
127      * @param ephemeralKey The ephemeralKey to set.
128      */
129     public void setExternalKey(byte[] ephemeralKey, String tokenIdentifier) {
130         this.ephemeralKey = ephemeralKey;
131         this.tokenIdentifier = tokenIdentifier;
132     }
133     
134     /**
135      * @param ephemeralKey The ephemeralKey to set.
136      */
137     public void setExternalKey(byte[] ephemeralKey, Element strElem) {
138         this.ephemeralKey = ephemeralKey;
139         this.strElem = strElem;
140     }
141     
142     /**
143      * @return Returns the tokenIdentifier.
144      */
145     public String getTokenIdentifier() {
146         return tokenIdentifier;
147     }
148     
149     /**
150      * Get the id generated during <code>prepare()</code>.
151      * 
152      * Returns the the value of wsu:Id attribute of the DerivedKeyToken element.
153      * 
154      * @return Return the wsu:Id of this token or null if <code>prepare()</code>
155      *         was not called before.
156      */
157     public String getId() {
158         return dktId;
159     }
160     
161     /**
162      * Set the label value of the client.
163      * @param clientLabel
164      */    
165     public void setClientLabel(String clientLabel) {
166         this.clientLabel = clientLabel;
167     }
168 
169     /**
170      * Set the label value of the service.
171      * @param serviceLabel
172      */
173     public void setServiceLabel(String serviceLabel) {
174         this.serviceLabel = serviceLabel;
175     }
176 
177     /**
178      * Initialize a WSSec Derived key.
179      * 
180      * The method prepares and initializes a WSSec derived key structure after the
181      * relevant information was set. This method also creates and initializes the
182      * derived token using the ephemeral key. After preparation references
183      * can be added, encrypted and signed as required.
184      * 
185      * This method does not add any element to the security header. This must be
186      * done explicitly.
187      * 
188      * @param doc The unsigned SOAP envelope as <code>Document</code>
189      * @throws WSSecurityException
190      */
191     public void prepare(Document doc) throws WSSecurityException, ConversationException {
192         
193         document = doc;
194 
195         // Create the derived keys
196         // At this point figure out the key length according to the symencAlgo
197         int offset = 0;
198         int length = getDerivedKeyLength();
199         byte[] label;
200         try {
201             label = (clientLabel + serviceLabel).getBytes("UTF-8");
202         } catch (UnsupportedEncodingException e) {
203             throw new WSSecurityException("UTF-8 encoding is not supported", e);
204         }
205         byte[] nonce = WSSecurityUtil.generateNonce(16);
206         
207         byte[] seed = new byte[label.length + nonce.length];
208         System.arraycopy(label, 0, seed, 0, label.length);
209         System.arraycopy(nonce, 0, seed, label.length, nonce.length);
210         
211         DerivationAlgorithm algo = 
212             AlgoFactory.getInstance(ConversationConstants.DerivationAlgorithm.P_SHA_1);
213         
214         derivedKeyBytes = algo.createKey(ephemeralKey, seed, offset, length);
215         
216         // Add the DKTs
217         dkt = new DerivedKeyToken(wscVersion, document);
218         dktId = getWsConfig().getIdAllocator().createId("DK-", dkt);
219         
220         dkt.setOffset(offset);
221         dkt.setLength(length);
222         dkt.setNonce(Base64.encode(nonce));
223         dkt.setID(dktId);
224         
225         if (strElem == null) {
226             SecurityTokenReference secRef = new SecurityTokenReference(document);
227             String strUri = getWsConfig().getIdAllocator().createSecureId("STR-", secRef);
228             secRef.setID(strUri);
229             
230             switch (keyIdentifierType) {
231             case WSConstants.CUSTOM_KEY_IDENTIFIER:
232                 secRef.setKeyIdentifier(customValueType, tokenIdentifier);
233                 if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(customValueType)) {
234                     secRef.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
235                 } else if (WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(customValueType)) {
236                     secRef.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
237                 } else if (WSConstants.WSS_ENC_KEY_VALUE_TYPE.equals(customValueType)) {
238                     secRef.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
239                 }
240                 break;
241             default:
242                 Reference ref = new Reference(document);
243                 
244                 if (tokenIdDirectId) {
245                     ref.setURI(tokenIdentifier);
246                 } else {
247                     ref.setURI("#" + tokenIdentifier);
248                 }
249                 if (customValueType != null && !"".equals(customValueType)) {
250                     ref.setValueType(customValueType);
251                 } 
252                 if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(customValueType)) {
253                     secRef.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
254                     ref.setValueType(customValueType);
255                 } else if (WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(customValueType)) {
256                     secRef.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
257                 } else if (WSConstants.WSS_ENC_KEY_VALUE_TYPE.equals(customValueType)) {
258                     secRef.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
259                     ref.setValueType(customValueType);
260                 } else if (KerberosSecurity.isKerberosToken(customValueType)) {
261                     secRef.addTokenType(customValueType);
262                     ref.setValueType(customValueType);
263                 } else if (WSConstants.WSC_SCT.equals(customValueType)
264                     || WSConstants.WSC_SCT_05_12.equals(customValueType)) {
265                     ref.setValueType(customValueType);
266                 } else if (!WSConstants.WSS_USERNAME_TOKEN_VALUE_TYPE.equals(customValueType)) {
267                     secRef.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
268                 } 
269 
270                 secRef.setReference(ref);
271             }
272             
273             dkt.setSecurityTokenReference(secRef); 
274         } else {
275             dkt.setSecurityTokenReference(strElem);
276         }
277     }
278 
279 
280     /**
281      * Prepend the DerivedKey element to the elements already in the Security
282      * header.
283      * 
284      * The method can be called any time after <code>prepare()</code>. This
285      * allows to insert the DerivedKey element at any position in the Security
286      * header.
287      * 
288      * @param secHeader The security header that holds the Signature element.
289      */
290     public void prependDKElementToHeader(WSSecHeader secHeader) {
291         WSSecurityUtil.prependChildElement(
292             secHeader.getSecurityHeader(), dkt.getElement()
293         );
294     }
295     
296     public void appendDKElementToHeader(WSSecHeader secHeader) {
297         Element secHeaderElement = secHeader.getSecurityHeader();
298         secHeaderElement.appendChild(dkt.getElement());
299     }
300 
301     /**
302      * @param wscVersion The wscVersion to set.
303      */
304     public void setWscVersion(int wscVersion) {
305         this.wscVersion = wscVersion;
306     }
307     
308     public Element getdktElement() {
309         return dkt.getElement();
310     }
311 
312     public void setDerivedKeyLength(int keyLength) {
313         derivedKeyLength = keyLength;
314     }
315 
316     public void setCustomValueType(String customValueType) {
317         this.customValueType = customValueType;
318     }
319     
320     public void setTokenIdDirectId(boolean b) {
321         tokenIdDirectId = b;
322     }
323 }