1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.wss4j.common.crypto;
21
22 import java.security.PublicKey;
23 import java.security.cert.X509Certificate;
24 import java.security.interfaces.*;
25 import java.util.Set;
26
27 import javax.xml.crypto.dsig.Reference;
28 import javax.xml.crypto.dsig.Transform;
29 import javax.xml.crypto.dsig.XMLSignature;
30
31 import org.apache.wss4j.common.ext.WSSecurityException;
32 import org.apache.xml.security.exceptions.DERDecodingException;
33 import org.apache.xml.security.utils.DERDecoderUtils;
34 import org.apache.xml.security.utils.KeyUtils;
35
36
37
38
39 public class AlgorithmSuiteValidator {
40
41 private static final org.slf4j.Logger LOG =
42 org.slf4j.LoggerFactory.getLogger(AlgorithmSuiteValidator.class);
43
44 private final AlgorithmSuite algorithmSuite;
45
46 public AlgorithmSuiteValidator(
47 AlgorithmSuite algorithmSuite
48 ) {
49 this.algorithmSuite = algorithmSuite;
50 }
51
52
53
54
55 public void checkSignatureMethod(
56 String signatureMethod
57 ) throws WSSecurityException {
58 Set<String> allowedSignatureMethods = algorithmSuite.getSignatureMethods();
59 if (!allowedSignatureMethods.isEmpty()
60 && !allowedSignatureMethods.contains(signatureMethod)) {
61 LOG.warn(
62 "SignatureMethod " + signatureMethod + " does not match required values"
63 );
64 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
65 }
66 }
67
68
69
70
71 public void checkC14nAlgorithm(
72 String c14nAlgorithm
73 ) throws WSSecurityException {
74 Set<String> allowedC14nAlgorithms = algorithmSuite.getC14nAlgorithms();
75 if (!allowedC14nAlgorithms.isEmpty() && !allowedC14nAlgorithms.contains(c14nAlgorithm)) {
76 LOG.warn(
77 "C14nMethod " + c14nAlgorithm + " does not match required value"
78 );
79 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
80 }
81 }
82
83
84
85
86 public void checkSignatureAlgorithms(
87 XMLSignature xmlSignature
88 ) throws WSSecurityException {
89
90 String signatureMethod =
91 xmlSignature.getSignedInfo().getSignatureMethod().getAlgorithm();
92 checkSignatureMethod(signatureMethod);
93
94
95 String c14nMethod =
96 xmlSignature.getSignedInfo().getCanonicalizationMethod().getAlgorithm();
97 checkC14nAlgorithm(c14nMethod);
98
99 for (Object refObject : xmlSignature.getSignedInfo().getReferences()) {
100 Reference reference = (Reference)refObject;
101
102 String digestMethod = reference.getDigestMethod().getAlgorithm();
103 Set<String> allowedDigestAlgorithms = algorithmSuite.getDigestAlgorithms();
104 if (!allowedDigestAlgorithms.isEmpty()
105 && !allowedDigestAlgorithms.contains(digestMethod)) {
106 LOG.warn(
107 "DigestMethod " + digestMethod + " does not match required value"
108 );
109 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
110 }
111
112
113 for (int i = 0; i < reference.getTransforms().size(); i++) {
114 Transform transform = (Transform)reference.getTransforms().get(i);
115 String algorithm = transform.getAlgorithm();
116 Set<String> allowedTransformAlgorithms =
117 algorithmSuite.getTransformAlgorithms();
118 if (!allowedTransformAlgorithms.isEmpty()
119 && !allowedTransformAlgorithms.contains(algorithm)) {
120 LOG.warn(
121 "Transform method " + algorithm + " does not match required value"
122 );
123 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
124 }
125 }
126 }
127 }
128
129 public void checkEncryptionKeyWrapAlgorithm(
130 String keyWrapAlgorithm
131 ) throws WSSecurityException {
132 Set<String> keyWrapAlgorithms = algorithmSuite.getKeyWrapAlgorithms();
133 if (!keyWrapAlgorithms.isEmpty()
134 && !keyWrapAlgorithms.contains(keyWrapAlgorithm)) {
135 LOG.warn(
136 "The Key transport method does not match the requirement"
137 );
138 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
139 }
140 }
141
142 public void checkKeyAgreementMethodAlgorithm(
143 String keyAgreementMethodAlgorithm
144 ) throws WSSecurityException {
145 Set<String> keyAgreementMethodAlgorithms = algorithmSuite.getKeyAgreementMethodAlgorithms();
146 if (!keyAgreementMethodAlgorithms.isEmpty()
147 && !keyAgreementMethodAlgorithms.contains(keyAgreementMethodAlgorithm)) {
148 LOG.warn(
149 "The Key agreement method does not match the requirement"
150 );
151 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
152 }
153 }
154
155
156
157
158
159
160
161
162 public void checkKeyDerivationFunction(
163 String keyDerivationFunction
164 ) throws WSSecurityException {
165 Set<String> keyDerivationFunctions = algorithmSuite.getDerivedKeyAlgorithms();
166 if (!keyDerivationFunctions.isEmpty()
167 && !keyDerivationFunctions.contains(keyDerivationFunction)) {
168 LOG.warn(
169 "The Key derivation function does not match the requirement"
170 );
171 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
172 }
173 }
174
175 public void checkSymmetricEncryptionAlgorithm(
176 String symmetricAlgorithm
177 ) throws WSSecurityException {
178 Set<String> encryptionMethods = algorithmSuite.getEncryptionMethods();
179 if (!encryptionMethods.isEmpty()
180 && !encryptionMethods.contains(symmetricAlgorithm)) {
181 LOG.warn(
182 "The encryption algorithm does not match the requirement"
183 );
184 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
185 }
186 }
187
188
189
190
191 public void checkAsymmetricKeyLength(
192 X509Certificate[] x509Certificates
193 ) throws WSSecurityException {
194 if (x509Certificates == null) {
195 return;
196 }
197
198 for (X509Certificate cert : x509Certificates) {
199 checkAsymmetricKeyLength(cert.getPublicKey());
200 }
201 }
202
203
204
205
206 public void checkAsymmetricKeyLength(
207 X509Certificate x509Certificate
208 ) throws WSSecurityException {
209 if (x509Certificate == null) {
210 return;
211 }
212
213 checkAsymmetricKeyLength(x509Certificate.getPublicKey());
214 }
215
216
217
218
219 public void checkAsymmetricKeyLength(
220 PublicKey publicKey
221 ) throws WSSecurityException {
222 if (publicKey == null) {
223 return;
224 }
225 if (publicKey instanceof RSAPublicKey) {
226 int modulus = ((RSAPublicKey)publicKey).getModulus().bitLength();
227 if (modulus < algorithmSuite.getMinimumAsymmetricKeyLength()
228 || modulus > algorithmSuite.getMaximumAsymmetricKeyLength()) {
229 LOG.warn(
230 "The asymmetric key length does not match the requirement"
231 );
232 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
233 }
234 } else if (publicKey instanceof DSAPublicKey) {
235 int length = ((DSAPublicKey)publicKey).getParams().getP().bitLength();
236 if (length < algorithmSuite.getMinimumAsymmetricKeyLength()
237 || length > algorithmSuite.getMaximumAsymmetricKeyLength()) {
238 LOG.warn(
239 "The asymmetric key length does not match the requirement"
240 );
241 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
242 }
243 } else if (publicKey instanceof ECPublicKey) {
244 final ECPublicKey ecpriv = (ECPublicKey) publicKey;
245 final java.security.spec.ECParameterSpec spec = ecpriv.getParams();
246 int length = spec.getOrder().bitLength();
247 if (length < algorithmSuite.getMinimumEllipticCurveKeyLength()
248 || length > algorithmSuite.getMaximumEllipticCurveKeyLength()) {
249 LOG.warn("The elliptic curve key length does not match the requirement");
250 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
251 }
252 } else {
253
254 int keySize = getEdECndXDHKeyLength(publicKey);
255 if (keySize < algorithmSuite.getMinimumEllipticCurveKeyLength()
256 || keySize > algorithmSuite.getMaximumEllipticCurveKeyLength()) {
257 LOG.warn(
258 "The asymmetric key length does not match the requirement"
259 );
260 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
261 }
262 }
263 }
264
265
266
267
268
269
270
271
272
273 private int getEdECndXDHKeyLength(PublicKey publicKey) throws WSSecurityException {
274 String keyAlgorithmOId;
275 try {
276 keyAlgorithmOId = DERDecoderUtils.getAlgorithmIdFromPublicKey(publicKey);
277 } catch (DERDecodingException e) {
278 LOG.warn("Can not parse the public key to determine key size!", e);
279 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
280 }
281 KeyUtils.KeyType keyType = KeyUtils.KeyType.getByOid(keyAlgorithmOId);
282 if (keyType == null) {
283 LOG.warn("An unknown public key was provided");
284 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
285 }
286
287 return switch (keyType) {
288 case ED25519, X25519 -> 256;
289 case ED448, X448 -> 456;
290 default -> {
291 LOG.warn(
292 "An unknown public key was provided"
293 );
294 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
295 }
296 };
297 }
298
299
300
301
302 public void checkSymmetricKeyLength(
303 int secretKeyLength
304 ) throws WSSecurityException {
305 if (secretKeyLength < (algorithmSuite.getMinimumSymmetricKeyLength() / 8)
306 || secretKeyLength > (algorithmSuite.getMaximumSymmetricKeyLength() / 8)) {
307 LOG.warn(
308 "The symmetric key length does not match the requirement"
309 );
310 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
311 }
312 }
313
314
315
316
317 public void checkSignatureDerivedKeyLength(
318 int derivedKeyLength
319 ) throws WSSecurityException {
320 int requiredKeyLength = algorithmSuite.getSignatureDerivedKeyLength();
321 if (requiredKeyLength > 0 && (derivedKeyLength / 8) != requiredKeyLength) {
322 LOG.warn(
323 "The signature derived key length of " + derivedKeyLength + " does not match"
324 + " the requirement of " + requiredKeyLength
325 );
326 }
327 }
328
329
330
331
332 public void checkEncryptionDerivedKeyLength(
333 int derivedKeyLength
334 ) throws WSSecurityException {
335 int requiredKeyLength = algorithmSuite.getEncryptionDerivedKeyLength();
336 if (requiredKeyLength > 0 && (derivedKeyLength / 8) != requiredKeyLength) {
337 LOG.warn(
338 "The encryption derived key length of " + derivedKeyLength + " does not match"
339 + " the requirement of " + requiredKeyLength
340 );
341 }
342 }
343
344
345
346
347 public void checkDerivedKeyAlgorithm(
348 String algorithm
349 ) throws WSSecurityException {
350 Set<String> derivedKeyAlgorithms = algorithmSuite.getDerivedKeyAlgorithms();
351 if (!derivedKeyAlgorithms.isEmpty()
352 && !derivedKeyAlgorithms.contains(algorithm)) {
353 LOG.warn(
354 "The Derived Key Algorithm does not match the requirement"
355 );
356 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
357 }
358 }
359
360 }