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.components.crypto;
21  
22  import org.apache.wss4j.common.util.SOAPUtil;
23  import org.apache.wss4j.dom.WSConstants;
24  import org.apache.wss4j.dom.common.KeystoreCallbackHandler;
25  
26  import org.apache.wss4j.dom.engine.WSSConfig;
27  import org.apache.wss4j.dom.engine.WSSecurityEngine;
28  import org.apache.wss4j.dom.engine.WSSecurityEngineResult;
29  import org.apache.wss4j.dom.handler.RequestData;
30  import org.apache.wss4j.dom.handler.WSHandlerResult;
31  import org.apache.wss4j.common.bsp.BSPRule;
32  import org.apache.wss4j.common.crypto.CertificateStore;
33  import org.apache.wss4j.common.crypto.Crypto;
34  import org.apache.wss4j.common.crypto.CryptoFactory;
35  import org.apache.wss4j.common.crypto.CryptoType;
36  import org.apache.wss4j.common.ext.WSSecurityException;
37  import org.apache.wss4j.common.util.XMLUtils;
38  import org.apache.wss4j.dom.message.WSSecHeader;
39  import org.apache.wss4j.dom.message.WSSecSignature;
40  
41  import org.junit.jupiter.api.Test;
42  import org.w3c.dom.Document;
43  
44  import java.security.cert.X509Certificate;
45  import java.util.Collections;
46  import java.util.List;
47  
48  import javax.security.auth.callback.CallbackHandler;
49  
50  import static org.junit.jupiter.api.Assertions.assertNotNull;
51  import static org.junit.jupiter.api.Assertions.assertThrows;
52  import static org.junit.jupiter.api.Assertions.assertTrue;
53  import static org.junit.jupiter.api.Assertions.fail;
54  
55  /**
56   * This is a test for the CertificateStore Crypto instance. This class does not know anything
57   * about Java KeyStores, but just wraps a list of trusted certificates.
58   */
59  public class CertificateStoreTest {
60      private static final org.slf4j.Logger LOG =
61          org.slf4j.LoggerFactory.getLogger(CertificateStoreTest.class);
62      private WSSecurityEngine secEngine = new WSSecurityEngine();
63      private Crypto senderCrypto = CryptoFactory.getInstance("wss40.properties");
64      private Crypto receiverCrypto;
65      private CallbackHandler keystoreCallbackHandler = new KeystoreCallbackHandler();
66  
67      public CertificateStoreTest() throws Exception {
68          CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
69          cryptoType.setAlias("wss40");
70          X509Certificate[] certs = senderCrypto.getX509Certificates(cryptoType);
71          receiverCrypto = new CertificateStore(certs);
72          WSSConfig.init();
73      }
74  
75      /**
76       * Test signing a SOAP message using a BST.
77       */
78      @Test
79      public void testSignatureDirectReference() throws Exception {
80          Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
81          WSSecHeader secHeader = new WSSecHeader(doc);
82          secHeader.insertSecurityHeader();
83  
84          WSSecSignature sign = new WSSecSignature(secHeader);
85          sign.setUserInfo("wss40", "security");
86          sign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
87  
88          Document signedDoc = sign.build(senderCrypto);
89  
90          if (LOG.isDebugEnabled()) {
91              String outputString =
92                  XMLUtils.prettyDocumentToString(signedDoc);
93              LOG.debug(outputString);
94          }
95          //
96          // Verify the signature
97          //
98          WSHandlerResult results = verify(signedDoc, receiverCrypto);
99          List<WSSecurityEngineResult> signatureResults =
100             results.getActionResults().get(WSConstants.SIGN);
101         WSSecurityEngineResult result = signatureResults.get(0);
102         X509Certificate cert =
103             (X509Certificate)result.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE);
104         assertNotNull(cert);
105     }
106 
107     /**
108      * Test signing a SOAP message using an X.509 Key Identifier.
109      */
110     @Test
111     public void testSignatureX509() throws Exception {
112         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
113         WSSecHeader secHeader = new WSSecHeader(doc);
114         secHeader.insertSecurityHeader();
115 
116         WSSecSignature sign = new WSSecSignature(secHeader);
117         sign.setUserInfo("wss40", "security");
118         sign.setKeyIdentifierType(WSConstants.X509_KEY_IDENTIFIER);
119 
120         Document signedDoc = sign.build(senderCrypto);
121 
122         if (LOG.isDebugEnabled()) {
123             String outputString =
124                 XMLUtils.prettyDocumentToString(signedDoc);
125             LOG.debug(outputString);
126         }
127         //
128         // Verify the signature
129         //
130         WSSecurityEngine newEngine = new WSSecurityEngine();
131         RequestData data = new RequestData();
132         data.setCallbackHandler(keystoreCallbackHandler);
133         data.setSigVerCrypto(receiverCrypto);
134         data.setIgnoredBSPRules(Collections.singletonList(BSPRule.R3063));
135         WSHandlerResult results = newEngine.processSecurityHeader(signedDoc, data);
136 
137         List<WSSecurityEngineResult> signatureResults =
138             results.getActionResults().get(WSConstants.SIGN);
139         WSSecurityEngineResult result = signatureResults.get(0);
140         X509Certificate cert =
141             (X509Certificate)result.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE);
142         assertNotNull(cert);
143     }
144 
145     /**
146      * Test signing a SOAP message using Issuer Serial.
147      */
148     @Test
149     public void testSignatureIssuerSerial() throws Exception {
150         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
151         WSSecHeader secHeader = new WSSecHeader(doc);
152         secHeader.insertSecurityHeader();
153 
154         WSSecSignature sign = new WSSecSignature(secHeader);
155         sign.setUserInfo("wss40", "security");
156         sign.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
157 
158         Document signedDoc = sign.build(senderCrypto);
159 
160         if (LOG.isDebugEnabled()) {
161             String outputString =
162                 XMLUtils.prettyDocumentToString(signedDoc);
163             LOG.debug(outputString);
164         }
165 
166         //
167         // Verify the signature
168         //
169         WSHandlerResult results = verify(signedDoc, receiverCrypto);
170 
171         List<WSSecurityEngineResult> signatureResults =
172             results.getActionResults().get(WSConstants.SIGN);
173         WSSecurityEngineResult result = signatureResults.get(0);
174         X509Certificate cert =
175             (X509Certificate)result.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE);
176         assertNotNull(cert);
177     }
178 
179     /**
180      * Test signing a SOAP message using a Thumbprint
181      */
182     @Test
183     public void testSignatureThumbprint() throws Exception {
184         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
185         WSSecHeader secHeader = new WSSecHeader(doc);
186         secHeader.insertSecurityHeader();
187 
188         WSSecSignature sign = new WSSecSignature(secHeader);
189         sign.setUserInfo("wss40", "security");
190         sign.setKeyIdentifierType(WSConstants.THUMBPRINT_IDENTIFIER);
191 
192         Document signedDoc = sign.build(senderCrypto);
193 
194         if (LOG.isDebugEnabled()) {
195             String outputString =
196                 XMLUtils.prettyDocumentToString(signedDoc);
197             LOG.debug(outputString);
198         }
199 
200         //
201         // Verify the signature
202         //
203         WSHandlerResult results = verify(signedDoc, receiverCrypto);
204         List<WSSecurityEngineResult> signatureResults =
205             results.getActionResults().get(WSConstants.SIGN);
206         WSSecurityEngineResult result = signatureResults.get(0);
207 
208         X509Certificate cert =
209             (X509Certificate)result.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE);
210         assertNotNull(cert);
211     }
212 
213     /**
214      * Test signing a SOAP message using a SKI Key Identifier
215      */
216     @Test
217     public void testSignatureSKI() throws Exception {
218         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
219         WSSecHeader secHeader = new WSSecHeader(doc);
220         secHeader.insertSecurityHeader();
221 
222         WSSecSignature sign = new WSSecSignature(secHeader);
223         sign.setUserInfo("wss40", "security");
224         sign.setKeyIdentifierType(WSConstants.SKI_KEY_IDENTIFIER);
225 
226         Document signedDoc = sign.build(senderCrypto);
227 
228         if (LOG.isDebugEnabled()) {
229             String outputString =
230                 XMLUtils.prettyDocumentToString(signedDoc);
231             LOG.debug(outputString);
232         }
233 
234         //
235         // Verify the signature
236         //
237         WSHandlerResult results = verify(signedDoc, receiverCrypto);
238 
239         List<WSSecurityEngineResult> signatureResults =
240             results.getActionResults().get(WSConstants.SIGN);
241         WSSecurityEngineResult result = signatureResults.get(0);
242         X509Certificate cert =
243             (X509Certificate)result.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE);
244         assertNotNull(cert);
245     }
246 
247     /**
248      * Test signing a SOAP message using a BST. The certificate is not known to the
249      * CertificateStore and so should throw an exception.
250      */
251     @Test
252     public void testSignatureDirectReferenceUntrusted() throws Exception {
253         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
254         WSSecHeader secHeader = new WSSecHeader(doc);
255         secHeader.insertSecurityHeader();
256 
257         WSSecSignature sign = new WSSecSignature(secHeader);
258         sign.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
259         sign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
260 
261         Document signedDoc = sign.build(CryptoFactory.getInstance());
262 
263         if (LOG.isDebugEnabled()) {
264             String outputString =
265                 XMLUtils.prettyDocumentToString(signedDoc);
266             LOG.debug(outputString);
267         }
268         //
269         // Verify the signature
270         //
271         try {
272             verify(signedDoc, receiverCrypto);
273             fail("Failure expected on an unknown certificate");
274         } catch (WSSecurityException ex) {
275             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILURE);
276         }
277     }
278 
279     @Test
280     public void testAliasNotAllowed() throws Exception {
281         CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
282         cryptoType.setAlias("wss40");
283         assertThrows(WSSecurityException.class, () -> {
284             receiverCrypto.getX509Certificates(cryptoType);
285         });
286     }
287 
288     /**
289      * Verifies the soap envelope
290      * <p/>
291      *
292      * @param doc
293      * @throws Exception Thrown when there is a problem in verification
294      */
295     private WSHandlerResult verify(Document doc, Crypto crypto) throws Exception {
296         WSHandlerResult results = secEngine.processSecurityHeader(
297             doc, null, keystoreCallbackHandler, crypto
298         );
299         if (LOG.isDebugEnabled()) {
300             LOG.debug("Verfied and decrypted message:");
301             String outputString =
302                 XMLUtils.prettyDocumentToString(doc);
303             LOG.debug(outputString);
304         }
305         return results;
306     }
307 
308 
309 }