1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.wss4j.dom.message;
21
22 import org.apache.wss4j.common.util.SOAPUtil;
23 import org.apache.wss4j.dom.WSConstants;
24 import org.apache.wss4j.dom.common.CustomHandler;
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.common.crypto.Crypto;
30 import org.apache.wss4j.common.crypto.CryptoFactory;
31 import org.apache.wss4j.common.crypto.Merlin;
32 import org.apache.wss4j.common.ext.WSSecurityException;
33 import org.apache.wss4j.common.util.XMLUtils;
34 import org.apache.wss4j.dom.handler.HandlerAction;
35 import org.apache.wss4j.dom.handler.RequestData;
36 import org.apache.wss4j.dom.handler.WSHandlerConstants;
37 import org.apache.wss4j.dom.handler.WSHandlerResult;
38
39 import org.bouncycastle.jce.provider.BouncyCastleProvider;
40 import org.junit.jupiter.api.Test;
41 import org.junit.jupiter.params.ParameterizedTest;
42 import org.junit.jupiter.params.provider.CsvSource;
43 import org.w3c.dom.Document;
44
45 import javax.security.auth.x500.X500Principal;
46 import java.security.Security;
47 import java.security.cert.X509Certificate;
48 import java.util.Collections;
49 import java.util.Properties;
50
51 import static org.junit.jupiter.api.Assertions.*;
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 public class SignatureCertTest {
82 private static final org.slf4j.Logger LOG =
83 org.slf4j.LoggerFactory.getLogger(SignatureCertTest.class);
84 private WSSecurityEngine secEngine = new WSSecurityEngine();
85 private Crypto crypto;
86 private Crypto cryptoCA;
87 private boolean isJDK16up;
88
89 public SignatureCertTest() throws Exception {
90 WSSConfig.init();
91 crypto = CryptoFactory.getInstance("wss40.properties");
92 cryptoCA = CryptoFactory.getInstance("wss40CA.properties");
93 try {
94 int javaVersion = Integer.getInteger("java.specification.version", 0);
95 isJDK16up = javaVersion >= 16;
96 } catch (NumberFormatException ex) {
97 LOG.warn("Error in retrieving the java version: [{}]", ex.getMessage());
98 }
99 }
100
101
102
103
104 @Test
105 public void testSignatureDirectReference() throws Exception {
106 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
107 WSSecHeader secHeader = new WSSecHeader(doc);
108 secHeader.insertSecurityHeader();
109
110 WSSecSignature sign = new WSSecSignature(secHeader);
111 sign.setUserInfo("wss40", "security");
112 sign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
113
114 Document signedDoc = sign.build(crypto);
115
116 if (LOG.isDebugEnabled()) {
117 String outputString =
118 XMLUtils.prettyDocumentToString(signedDoc);
119 LOG.debug(outputString);
120 }
121
122
123
124 WSHandlerResult results = verify(signedDoc, cryptoCA);
125 WSSecurityEngineResult result =
126 results.getActionResults().get(WSConstants.SIGN).get(0);
127 X509Certificate cert =
128 (X509Certificate)result.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE);
129 assertNotNull(cert);
130 }
131
132
133
134
135
136 @Test
137 public void testSignatureDirectReferenceCACert() throws Exception {
138 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
139 WSSecHeader secHeader = new WSSecHeader(doc);
140 secHeader.insertSecurityHeader();
141
142 WSSecSignature sign = new WSSecSignature(secHeader);
143 sign.setUserInfo("wss40", "security");
144 sign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
145 sign.setUseSingleCertificate(false);
146
147 Document signedDoc = sign.build(crypto);
148
149 if (LOG.isDebugEnabled()) {
150 String outputString =
151 XMLUtils.prettyDocumentToString(signedDoc);
152 LOG.debug("BST CA Cert");
153 LOG.debug(outputString);
154 }
155
156
157
158 WSHandlerResult results = verify(signedDoc, cryptoCA);
159 WSSecurityEngineResult result =
160 results.getActionResults().get(WSConstants.SIGN).get(0);
161 X509Certificate cert =
162 (X509Certificate)result.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE);
163 assertNotNull(cert);
164 X509Certificate[] certs =
165 (X509Certificate[])result.get(WSSecurityEngineResult.TAG_X509_CERTIFICATES);
166 assertTrue(certs != null && certs.length == 2);
167 }
168
169
170
171
172
173
174
175 @Test
176 public void testSignatureIssuerSerial() throws Exception {
177 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
178 WSSecHeader secHeader = new WSSecHeader(doc);
179 secHeader.insertSecurityHeader();
180
181 WSSecSignature sign = new WSSecSignature(secHeader);
182 sign.setUserInfo("wss40", "security");
183 sign.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
184
185 Document signedDoc = sign.build(crypto);
186
187 if (LOG.isDebugEnabled()) {
188 String outputString =
189 XMLUtils.prettyDocumentToString(signedDoc);
190 LOG.debug(outputString);
191 }
192
193 try {
194 verify(signedDoc, cryptoCA);
195 fail("Failure expected on issuer serial");
196 } catch (WSSecurityException ex) {
197 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_CHECK);
198 }
199 }
200
201
202
203
204
205
206 @Test
207 public void testSignatureBadCACert() throws Exception {
208 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
209 WSSecHeader secHeader = new WSSecHeader(doc);
210 secHeader.insertSecurityHeader();
211
212 WSSecSignature sign = new WSSecSignature(secHeader);
213 sign.setUserInfo("wss40expca", "security");
214 sign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
215
216 Document signedDoc =
217 sign.build(CryptoFactory.getInstance("wss40badca.properties"));
218
219 if (LOG.isDebugEnabled()) {
220 String outputString =
221 XMLUtils.prettyDocumentToString(signedDoc);
222 LOG.debug(outputString);
223 }
224
225
226
227 try {
228 verify(signedDoc, CryptoFactory.getInstance("wss40badcatrust.properties"));
229 fail("Failure expected on bad CA cert!");
230 } catch (WSSecurityException ex) {
231 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILURE);
232 }
233 }
234
235
236
237
238 @Test
239 public void testMultipleCertsWSHandler() throws Exception {
240 final WSSConfig cfg = WSSConfig.getNewInstance();
241 final RequestData reqData = new RequestData();
242 reqData.setWssConfig(cfg);
243 reqData.setUsername("wss40");
244 java.util.Map<String, String> config = new java.util.TreeMap<>();
245 config.put(WSHandlerConstants.SIG_PROP_FILE, "wss40.properties");
246 config.put("password", "security");
247 config.put(WSHandlerConstants.SIG_KEY_ID, "DirectReference");
248 config.put(WSHandlerConstants.USE_SINGLE_CERTIFICATE, "false");
249 reqData.setMsgContext(config);
250
251 final Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
252 CustomHandler handler = new CustomHandler();
253 HandlerAction action = new HandlerAction(WSConstants.SIGN);
254 handler.send(
255 doc,
256 reqData,
257 Collections.singletonList(action),
258 true
259 );
260
261
262
263
264 WSHandlerResult results = verify(doc, cryptoCA);
265 WSSecurityEngineResult result =
266 results.getActionResults().get(WSConstants.SIGN).get(0);
267 X509Certificate cert =
268 (X509Certificate)result.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE);
269 assertNotNull(cert);
270 X509Certificate[] certs =
271 (X509Certificate[])result.get(WSSecurityEngineResult.TAG_X509_CERTIFICATES);
272 assertTrue(certs != null && certs.length == 2);
273 }
274
275 @Test
276 public void testExpiredCert() throws Exception {
277 Properties clientProperties = new Properties();
278 clientProperties.put("org.apache.wss4j.crypto.provider",
279 "org.apache.wss4j.common.crypto.Merlin");
280 clientProperties.put("org.apache.wss4j.crypto.merlin.keystore.type", "jks");
281 clientProperties.put("org.apache.wss4j.crypto.merlin.keystore.password", "security");
282 clientProperties.put("org.apache.wss4j.crypto.merlin.keystore.alias", "wss40exp");
283 clientProperties.put("org.apache.wss4j.crypto.merlin.keystore.file", "keys/wss40exp.jks");
284
285 Crypto clientCrypto = new Merlin(clientProperties, this.getClass().getClassLoader(), null);
286
287 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
288 WSSecHeader secHeader = new WSSecHeader(doc);
289 secHeader.insertSecurityHeader();
290
291 WSSecSignature sign = new WSSecSignature(secHeader);
292 sign.setUserInfo("wss40exp", "security");
293 sign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
294
295 Document signedDoc = sign.build(clientCrypto);
296
297 if (LOG.isDebugEnabled()) {
298 String outputString =
299 XMLUtils.prettyDocumentToString(signedDoc);
300 LOG.debug(outputString);
301 }
302
303
304
305 WSSecurityEngine newEngine = new WSSecurityEngine();
306 try {
307 newEngine.processSecurityHeader(doc, null, null, cryptoCA);
308 fail("Failure expected on an expired cert");
309 } catch (WSSecurityException ex) {
310 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILURE);
311 }
312 }
313
314 @Test
315 public void testExpiredCertInKeystore() throws Exception {
316 Properties clientProperties = new Properties();
317 clientProperties.put("org.apache.wss4j.crypto.provider",
318 "org.apache.wss4j.common.crypto.Merlin");
319 clientProperties.put("org.apache.wss4j.crypto.merlin.keystore.type", "jks");
320 clientProperties.put("org.apache.wss4j.crypto.merlin.keystore.password", "security");
321 clientProperties.put("org.apache.wss4j.crypto.merlin.keystore.alias", "wss40exp");
322 clientProperties.put("org.apache.wss4j.crypto.merlin.keystore.file", "keys/wss40exp.jks");
323
324 Crypto clientCrypto = new Merlin(clientProperties, this.getClass().getClassLoader(), null);
325
326 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
327 WSSecHeader secHeader = new WSSecHeader(doc);
328 secHeader.insertSecurityHeader();
329
330 WSSecSignature sign = new WSSecSignature(secHeader);
331 sign.setUserInfo("wss40exp", "security");
332 sign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
333
334 Document signedDoc = sign.build(clientCrypto);
335
336 if (LOG.isDebugEnabled()) {
337 String outputString =
338 XMLUtils.prettyDocumentToString(signedDoc);
339 LOG.debug(outputString);
340 }
341
342
343
344 WSSecurityEngine newEngine = new WSSecurityEngine();
345 try {
346 newEngine.processSecurityHeader(doc, null, null, clientCrypto);
347 fail("Failure expected on an expired cert");
348 } catch (WSSecurityException ex) {
349 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_CHECK);
350 }
351 }
352
353
354
355
356 @ParameterizedTest
357 @CsvSource({
358 "ed25519, 'Algorithm=\"http://www.w3.org/2021/04/xmldsig-more#eddsa-ed25519\"', 'CN=ed25519, OU=eDeliveryAS4-2.0, OU=wss4j, O=apache, C=EU'",
359 "ed448, 'Algorithm=\"http://www.w3.org/2021/04/xmldsig-more#eddsa-ed448\"', 'CN=ed448, OU=eDeliveryAS4-2.0, OU=wss4j, O=apache, C=EU'",
360 })
361 public void testEdDSASignatureDirectReference(String alias, String algorithm, X500Principal certSubjectDN) throws Exception {
362 try {
363
364 if (!isJDK16up) {
365 Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
366 }
367
368 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
369 WSSecHeader secHeader = new WSSecHeader(doc);
370 secHeader.insertSecurityHeader();
371
372 Crypto ed_crypto = CryptoFactory.getInstance("wss-eddsa.properties");
373
374 WSSecSignature builder = new WSSecSignature(secHeader);
375 builder.setUserInfo(alias, "security");
376 builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
377 Document signedDoc = builder.build(ed_crypto);
378
379 String outputString =
380 XMLUtils.prettyDocumentToString(signedDoc);
381 if (LOG.isDebugEnabled()) {
382 LOG.debug(outputString);
383 }
384
385 assertTrue(outputString.contains(algorithm));
386
387 final WSHandlerResult results = verify(signedDoc, ed_crypto);
388
389 WSSecurityEngineResult actionResult =
390 results.getActionResults().get(WSConstants.SIGN).get(0);
391 assertNotNull(actionResult);
392
393 java.security.Principal principal =
394 (java.security.Principal) actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
395 assertTrue(principal instanceof X500Principal);
396 X500Principal x500Principal = (X500Principal) principal;
397 assertEquals(certSubjectDN, x500Principal);
398
399 } finally {
400 if (!isJDK16up) {
401 Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
402 }
403 }
404 }
405
406
407
408
409
410
411
412
413 private WSHandlerResult verify(Document doc, Crypto crypto) throws Exception {
414 WSHandlerResult results = secEngine.processSecurityHeader(
415 doc, null, null, crypto
416 );
417 if (LOG.isDebugEnabled()) {
418 LOG.debug("Verfied and decrypted message:");
419 String outputString =
420 XMLUtils.prettyDocumentToString(doc);
421 LOG.debug(outputString);
422 }
423 return results;
424 }
425
426
427 }