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 java.util.List;
23  
24  import javax.crypto.KeyGenerator;
25  import javax.crypto.SecretKey;
26  import javax.xml.crypto.dsig.SignatureMethod;
27  
28  import org.apache.ws.security.WSConstants;
29  import org.apache.ws.security.WSSConfig;
30  import org.apache.ws.security.WSSecurityEngine;
31  import org.apache.ws.security.WSSecurityEngineResult;
32  import org.apache.ws.security.WSSecurityException;
33  import org.apache.ws.security.common.SOAPUtil;
34  import org.apache.ws.security.common.SecretKeyCallbackHandler;
35  import org.apache.ws.security.components.crypto.AlgorithmSuite;
36  import org.apache.ws.security.components.crypto.Crypto;
37  import org.apache.ws.security.components.crypto.CryptoFactory;
38  import org.apache.ws.security.handler.RequestData;
39  import org.apache.ws.security.util.WSSecurityUtil;
40  import org.apache.ws.security.util.XMLUtils;
41  import org.apache.xml.security.utils.Base64;
42  import org.w3c.dom.Document;
43  import org.w3c.dom.Element;
44  
45  
46  /**
47   * A set of test-cases for signing and verifying SOAP requests when specifying an 
48   * AlgorithmSuite policy.
49   */
50  public class SignatureAlgorithmSuiteTest extends org.junit.Assert {
51      private static final org.apache.commons.logging.Log LOG = 
52          org.apache.commons.logging.LogFactory.getLog(SignatureAlgorithmSuiteTest.class);
53      
54      private Crypto crypto = null;
55      
56      public SignatureAlgorithmSuiteTest() throws Exception {
57          WSSConfig.init();
58          crypto = CryptoFactory.getInstance();
59      }
60  
61      @org.junit.Test
62      public void testSignature() throws Exception {
63          WSSecSignature builder = new WSSecSignature();
64          builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
65          builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
66          builder.setSignatureAlgorithm(WSConstants.RSA_SHA1);
67  
68          Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
69          WSSecHeader secHeader = new WSSecHeader();
70          secHeader.insertSecurityHeader(doc);
71          Document signedDoc = builder.build(doc, crypto, secHeader);
72  
73          if (LOG.isDebugEnabled()) {
74              String outputString = 
75                  XMLUtils.PrettyDocumentToString(signedDoc);
76              LOG.debug(outputString);
77          }
78          
79          Element securityHeader = WSSecurityUtil.getSecurityHeader(signedDoc, null);
80          AlgorithmSuite algorithmSuite = createAlgorithmSuite();
81          
82          verify(securityHeader, algorithmSuite, crypto);
83          
84          algorithmSuite.setMinimumAsymmetricKeyLength(1024);
85          
86          try {
87              verify(securityHeader, algorithmSuite, crypto);
88              fail("Expected failure as 512-bit keys are not allowed");
89          } catch (WSSecurityException ex) {
90              // expected
91          }
92      }
93      
94      @org.junit.Test
95      public void testSignatureMethodDSA() throws Exception {
96          Crypto dsaCrypto = CryptoFactory.getInstance("wss40.properties");
97          
98          WSSecSignature builder = new WSSecSignature();
99          builder.setUserInfo("wss40DSA", "security");
100         builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
101         builder.setSignatureAlgorithm(WSConstants.DSA);
102 
103         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
104         WSSecHeader secHeader = new WSSecHeader();
105         secHeader.insertSecurityHeader(doc);
106         Document signedDoc = builder.build(doc, dsaCrypto, secHeader);
107 
108         if (LOG.isDebugEnabled()) {
109             String outputString = 
110                 XMLUtils.PrettyDocumentToString(signedDoc);
111             LOG.debug(outputString);
112         }
113         
114         Element securityHeader = WSSecurityUtil.getSecurityHeader(signedDoc, null);
115         AlgorithmSuite algorithmSuite = createAlgorithmSuite();
116         
117         try {
118             verify(securityHeader, algorithmSuite, dsaCrypto);
119             fail("Expected failure as DSA is not allowed");
120         } catch (WSSecurityException ex) {
121             // expected
122         }
123         
124         algorithmSuite.addSignatureMethod(WSConstants.DSA);
125         verify(securityHeader, algorithmSuite, dsaCrypto);
126     }
127     
128     @org.junit.Test
129     public void testSymmetricKey() throws Exception {
130         
131         KeyGenerator keyGen = KeyGenerator.getInstance("AES");
132         keyGen.init(128);
133         SecretKey key = keyGen.generateKey();
134         byte[] keyData = key.getEncoded();
135         
136         WSSecSignature builder = new WSSecSignature();
137         builder.setKeyIdentifierType(WSConstants.ENCRYPTED_KEY_SHA1_IDENTIFIER);
138         builder.setSecretKey(keyData);
139         builder.setSignatureAlgorithm(SignatureMethod.HMAC_SHA1);
140         
141         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
142         WSSecHeader secHeader = new WSSecHeader();
143         secHeader.insertSecurityHeader(doc);
144         Document signedDoc = builder.build(doc, crypto, secHeader);
145 
146         if (LOG.isDebugEnabled()) {
147             String outputString = 
148                 XMLUtils.PrettyDocumentToString(signedDoc);
149             LOG.debug(outputString);
150         }
151         
152         byte[] encodedBytes = WSSecurityUtil.generateDigest(keyData);
153         String identifier = Base64.encode(encodedBytes);
154         SecretKeyCallbackHandler secretKeyCallbackHandler = new SecretKeyCallbackHandler();
155         secretKeyCallbackHandler.addSecretKey(identifier, keyData);
156         
157         Element securityHeader = WSSecurityUtil.getSecurityHeader(signedDoc, null);
158         AlgorithmSuite algorithmSuite = createAlgorithmSuite();
159         
160         WSSecurityEngine secEngine = new WSSecurityEngine();
161         RequestData data = new RequestData();
162         data.setSigCrypto(crypto);
163         data.setCallbackHandler(secretKeyCallbackHandler);
164         data.setAlgorithmSuite(algorithmSuite);
165         
166         try {
167             secEngine.processSecurityHeader(securityHeader, data);
168             fail("Expected failure as HMAC-SHA1 is not allowed");
169         } catch (WSSecurityException ex) {
170             // expected
171         }
172         
173         algorithmSuite.addSignatureMethod(WSConstants.HMAC_SHA1);
174         secEngine.processSecurityHeader(securityHeader, data);
175         
176         algorithmSuite.setMinimumSymmetricKeyLength(256);
177         try {
178             secEngine.processSecurityHeader(securityHeader, data);
179             fail("Expected failure as a 128 bit key is not allowed");
180         } catch (WSSecurityException ex) {
181             // expected
182         }
183         
184         algorithmSuite.setMinimumSymmetricKeyLength(64);
185         algorithmSuite.setMaximumSymmetricKeyLength(120);
186         try {
187             secEngine.processSecurityHeader(securityHeader, data);
188             fail("Expected failure as a 128 bit key is not allowed");
189         } catch (WSSecurityException ex) {
190             // expected
191         }
192     }
193     
194     @org.junit.Test
195     public void testC14nMethod() throws Exception {
196         WSSecSignature builder = new WSSecSignature();
197         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
198         builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
199         builder.setSignatureAlgorithm(WSConstants.RSA_SHA1);
200         builder.setSigCanonicalization(WSConstants.C14N_EXCL_WITH_COMMENTS);
201 
202         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
203         WSSecHeader secHeader = new WSSecHeader();
204         secHeader.insertSecurityHeader(doc);
205         Document signedDoc = builder.build(doc, crypto, secHeader);
206 
207         if (LOG.isDebugEnabled()) {
208             String outputString = 
209                 XMLUtils.PrettyDocumentToString(signedDoc);
210             LOG.debug(outputString);
211         }
212 
213         Element securityHeader = WSSecurityUtil.getSecurityHeader(signedDoc, null);
214         AlgorithmSuite algorithmSuite = createAlgorithmSuite();
215         
216         try {
217             verify(securityHeader, algorithmSuite, crypto);
218             fail("Expected failure as C14n algorithm is not allowed");
219         } catch (WSSecurityException ex) {
220             // expected
221         }
222         
223         algorithmSuite.addC14nAlgorithm(WSConstants.C14N_EXCL_WITH_COMMENTS);
224         verify(securityHeader, algorithmSuite, crypto);
225     }
226     
227     @org.junit.Test
228     public void testDigestMethod() throws Exception {
229         WSSecSignature builder = new WSSecSignature();
230         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
231         builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
232         builder.setSignatureAlgorithm(WSConstants.RSA_SHA1);
233         builder.setDigestAlgo(WSConstants.SHA256);
234 
235         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
236         WSSecHeader secHeader = new WSSecHeader();
237         secHeader.insertSecurityHeader(doc);
238         Document signedDoc = builder.build(doc, crypto, secHeader);
239 
240         if (LOG.isDebugEnabled()) {
241             String outputString = 
242                 XMLUtils.PrettyDocumentToString(signedDoc);
243             LOG.debug(outputString);
244         }
245 
246         Element securityHeader = WSSecurityUtil.getSecurityHeader(signedDoc, null);
247         AlgorithmSuite algorithmSuite = createAlgorithmSuite();
248         
249         try {
250             verify(securityHeader, algorithmSuite, crypto);
251             fail("Expected failure as Digest algorithm is not allowed");
252         } catch (WSSecurityException ex) {
253             // expected
254         }
255         
256         algorithmSuite.addDigestAlgorithm(WSConstants.SHA256);
257         verify(securityHeader, algorithmSuite, crypto);
258     }
259     
260     private AlgorithmSuite createAlgorithmSuite() {
261         AlgorithmSuite algorithmSuite = new AlgorithmSuite();
262         algorithmSuite.addSignatureMethod(WSConstants.RSA_SHA1);
263         algorithmSuite.setMinimumAsymmetricKeyLength(512);
264         algorithmSuite.addC14nAlgorithm(WSConstants.C14N_EXCL_OMIT_COMMENTS);
265         algorithmSuite.addDigestAlgorithm(WSConstants.SHA1);
266         
267         return algorithmSuite;
268     }
269 
270     private List<WSSecurityEngineResult> verify(
271         Element securityHeader, AlgorithmSuite algorithmSuite, Crypto sigVerCrypto
272     ) throws Exception {
273         WSSecurityEngine secEngine = new WSSecurityEngine();
274         RequestData data = new RequestData();
275         data.setSigCrypto(sigVerCrypto);
276         
277         data.setAlgorithmSuite(algorithmSuite);
278         
279         WSSConfig wssConfig = WSSConfig.getNewInstance();
280         wssConfig.setWsiBSPCompliant(false);
281         data.setWssConfig(wssConfig);
282         
283         return secEngine.processSecurityHeader(securityHeader, data);
284     }
285 
286 }