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.ws.security.components.crypto;
21  
22  import java.security.PublicKey;
23  import java.security.cert.X509Certificate;
24  import java.security.interfaces.DSAPublicKey;
25  import java.security.interfaces.RSAPublicKey;
26  import java.util.Set;
27  
28  import javax.xml.crypto.dsig.Reference;
29  import javax.xml.crypto.dsig.Transform;
30  import javax.xml.crypto.dsig.XMLSignature;
31  
32  import org.apache.ws.security.WSSecurityException;
33  
34  /**
35   * Validate signature/encryption/etc. algorithms against an AlgorithmSuite policy.
36   */
37  public class AlgorithmSuiteValidator {
38      
39      private static final org.apache.commons.logging.Log LOG = 
40          org.apache.commons.logging.LogFactory.getLog(AlgorithmSuiteValidator.class);
41      
42      private final AlgorithmSuite algorithmSuite;
43      
44      public AlgorithmSuiteValidator(
45          AlgorithmSuite algorithmSuite
46      ) {
47          this.algorithmSuite = algorithmSuite;
48      }
49      
50      /**
51       * Check the Signature Method
52       */
53      public void checkSignatureMethod(
54          String signatureMethod
55      ) throws WSSecurityException {
56          Set<String> allowedSignatureMethods = algorithmSuite.getSignatureMethods();
57          if (!allowedSignatureMethods.isEmpty()
58              && !allowedSignatureMethods.contains(signatureMethod)) {
59              LOG.debug(
60                  "SignatureMethod " + signatureMethod + " does not match required values"
61              );
62              throw new WSSecurityException(WSSecurityException.INVALID_SECURITY);
63          }
64      }
65      
66      /**
67       * Check the C14n Algorithm
68       */
69      public void checkC14nAlgorithm(
70          String c14nAlgorithm
71      ) throws WSSecurityException {
72          Set<String> allowedC14nAlgorithms = algorithmSuite.getC14nAlgorithms();
73          if (!allowedC14nAlgorithms.isEmpty() && !allowedC14nAlgorithms.contains(c14nAlgorithm)) {
74              LOG.debug(
75                  "C14nMethod " + c14nAlgorithm + " does not match required value"
76              );
77              throw new WSSecurityException(WSSecurityException.INVALID_SECURITY);
78          }
79      }
80      
81      /**
82       * Check the Signature Algorithms
83       */
84      public void checkSignatureAlgorithms(
85          XMLSignature xmlSignature
86      ) throws WSSecurityException {
87          // Signature Algorithm
88          String signatureMethod = 
89              xmlSignature.getSignedInfo().getSignatureMethod().getAlgorithm();
90          checkSignatureMethod(signatureMethod);
91              
92          // C14n Algorithm
93          String c14nMethod = 
94              xmlSignature.getSignedInfo().getCanonicalizationMethod().getAlgorithm();
95          checkC14nAlgorithm(c14nMethod);
96          
97          for (Object refObject : xmlSignature.getSignedInfo().getReferences()) {
98              Reference reference = (Reference)refObject;
99              // Digest Algorithm
100             String digestMethod = reference.getDigestMethod().getAlgorithm();
101             Set<String> allowedDigestAlgorithms = algorithmSuite.getDigestAlgorithms();
102             if (!allowedDigestAlgorithms.isEmpty()
103                     && !allowedDigestAlgorithms.contains(digestMethod)) {
104                 LOG.debug(
105                     "DigestMethod " + digestMethod + " does not match required value"
106                 );
107                 throw new WSSecurityException(WSSecurityException.INVALID_SECURITY);
108             }
109             
110             // Transform Algorithms
111             for (int i = 0; i < reference.getTransforms().size(); i++) {
112                 Transform transform = (Transform)reference.getTransforms().get(i);
113                 String algorithm = transform.getAlgorithm();
114                 Set<String> allowedTransformAlgorithms = 
115                         algorithmSuite.getTransformAlgorithms();
116                 if (!allowedTransformAlgorithms.isEmpty() 
117                         && !allowedTransformAlgorithms.contains(algorithm)) {
118                     LOG.debug(
119                         "Transform method " + algorithm + " does not match required value"
120                     );
121                     throw new WSSecurityException(WSSecurityException.INVALID_SECURITY);
122                 }
123             }
124         }
125     }
126     
127     public void checkEncryptionKeyWrapAlgorithm(
128         String keyWrapAlgorithm
129     ) throws WSSecurityException {
130         Set<String> keyWrapAlgorithms = algorithmSuite.getKeyWrapAlgorithms();
131         if (!keyWrapAlgorithms.isEmpty()
132             && !keyWrapAlgorithms.contains(keyWrapAlgorithm)) {
133             LOG.debug(
134                 "The Key transport method does not match the requirement"
135             );
136             throw new WSSecurityException(WSSecurityException.INVALID_SECURITY);
137         }
138     }
139     
140     public void checkSymmetricEncryptionAlgorithm(
141         String symmetricAlgorithm
142     ) throws WSSecurityException {
143         Set<String> encryptionMethods = algorithmSuite.getEncryptionMethods();
144         if (!encryptionMethods.isEmpty()
145             && !encryptionMethods.contains(symmetricAlgorithm)) {
146             LOG.debug(
147                 "The encryption algorithm does not match the requirement"
148             );
149             throw new WSSecurityException(WSSecurityException.INVALID_SECURITY);
150         }
151     }
152 
153     /**
154      * Check the asymmetric key length
155      */
156     public void checkAsymmetricKeyLength(
157         X509Certificate x509Certificate
158     ) throws WSSecurityException {
159         if (x509Certificate == null) {
160             return;
161         }
162         
163         checkAsymmetricKeyLength(x509Certificate.getPublicKey());
164     }
165     
166     /**
167      * Check the asymmetric key length
168      */
169     public void checkAsymmetricKeyLength(
170         PublicKey publicKey
171     ) throws WSSecurityException {
172         if (publicKey == null) {
173             return;
174         }
175         if (publicKey instanceof RSAPublicKey) {
176             int modulus = ((RSAPublicKey)publicKey).getModulus().bitLength();
177             if (modulus < algorithmSuite.getMinimumAsymmetricKeyLength()
178                 || modulus > algorithmSuite.getMaximumAsymmetricKeyLength()) {
179                 LOG.debug(
180                     "The asymmetric key length does not match the requirement"
181                 );
182                 throw new WSSecurityException(WSSecurityException.INVALID_SECURITY);
183             }
184         } else if (publicKey instanceof DSAPublicKey) {
185             int length = ((DSAPublicKey)publicKey).getParams().getP().bitLength();
186             if (length < algorithmSuite.getMinimumAsymmetricKeyLength()
187                 || length > algorithmSuite.getMaximumAsymmetricKeyLength()) {
188                 LOG.debug(
189                     "The asymmetric key length does not match the requirement"
190                 );
191                 throw new WSSecurityException(WSSecurityException.INVALID_SECURITY);
192             }
193         } else {
194             LOG.debug(
195                 "An unknown public key was provided"
196             );
197             throw new WSSecurityException(WSSecurityException.INVALID_SECURITY);
198         }
199     }
200     
201     /**
202      * Check the symmetric key length
203      */
204     public void checkSymmetricKeyLength(
205         int secretKeyLength
206     ) throws WSSecurityException {
207         if (secretKeyLength < (algorithmSuite.getMinimumSymmetricKeyLength() / 8)
208             || secretKeyLength > (algorithmSuite.getMaximumSymmetricKeyLength() / 8)) {
209             LOG.debug(
210                 "The symmetric key length does not match the requirement"
211             );
212             throw new WSSecurityException(WSSecurityException.INVALID_SECURITY);
213         }
214     }
215     
216     /**
217      * Check Signature Derived Key length (in bytes)
218      */
219     public void checkSignatureDerivedKeyLength(
220         int derivedKeyLength
221     ) throws WSSecurityException {
222         int requiredKeyLength = algorithmSuite.getSignatureDerivedKeyLength();
223         if (requiredKeyLength > 0 && (derivedKeyLength / 8) != requiredKeyLength) {
224             LOG.debug(
225                 "The signature derived key length of " + derivedKeyLength + " does not match"
226                 + "the requirement of " + requiredKeyLength
227             );
228         }
229     }
230     
231     /**
232      * Check Encryption Derived Key length (in bytes)
233      */
234     public void checkEncryptionDerivedKeyLength(
235         int derivedKeyLength
236     ) throws WSSecurityException {
237         int requiredKeyLength = algorithmSuite.getEncryptionDerivedKeyLength();
238         if (requiredKeyLength > 0 && (derivedKeyLength / 8) != requiredKeyLength) {
239             LOG.debug(
240                 "The encryption derived key length of " + derivedKeyLength + " does not match"
241                 + "the requirement of " + requiredKeyLength
242             );
243         }
244     }
245     
246     /**
247      * Check Derived Key algorithm
248      */
249     public void checkDerivedKeyAlgorithm(
250         String algorithm
251     ) throws WSSecurityException {
252         Set<String> derivedKeyAlgorithms = algorithmSuite.getDerivedKeyAlgorithms();
253         if (!derivedKeyAlgorithms.isEmpty()
254             && !derivedKeyAlgorithms.contains(algorithm)) {
255             LOG.debug(
256                 "The Derived Key Algorithm does not match the requirement"
257             );
258             throw new WSSecurityException(WSSecurityException.INVALID_SECURITY);
259         }
260     }
261         
262 }