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