View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /**
6    * Licensed to the Apache Software Foundation (ASF) under one
7    * or more contributor license agreements. See the NOTICE file
8    * distributed with this work for additional information
9    * regarding copyright ownership. The ASF licenses this file
10   * to you under the Apache License, Version 2.0 (the
11   * "License"); you may not use this file except in compliance
12   * with the License. You may obtain a copy of the License at
13   *
14   * http://www.apache.org/licenses/LICENSE-2.0
15   *
16   * Unless required by applicable law or agreed to in writing,
17   * software distributed under the License is distributed on an
18   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19   * KIND, either express or implied. See the License for the
20   * specific language governing permissions and limitations
21   * under the License.
22   */
23  package com.sun.org.apache.xml.internal.security.algorithms;
24  
25  import java.security.Key;
26  import java.security.SecureRandom;
27  import java.security.spec.AlgorithmParameterSpec;
28  import java.util.Map;
29  import java.util.concurrent.ConcurrentHashMap;
30  
31  import com.sun.org.apache.xml.internal.security.algorithms.implementations.IntegrityHmac;
32  import com.sun.org.apache.xml.internal.security.algorithms.implementations.SignatureBaseRSA;
33  import com.sun.org.apache.xml.internal.security.algorithms.implementations.SignatureDSA;
34  import com.sun.org.apache.xml.internal.security.algorithms.implementations.SignatureECDSA;
35  import com.sun.org.apache.xml.internal.security.exceptions.AlgorithmAlreadyRegisteredException;
36  import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException;
37  import com.sun.org.apache.xml.internal.security.signature.XMLSignature;
38  import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException;
39  import com.sun.org.apache.xml.internal.security.utils.Constants;
40  import org.w3c.dom.Attr;
41  import org.w3c.dom.Document;
42  import org.w3c.dom.Element;
43  
44  /**
45   * Allows selection of digital signature's algorithm, private keys, other
46   * security parameters, and algorithm's ID.
47   *
48   * @author Christian Geuer-Pollmann
49   */
50  public class SignatureAlgorithm extends Algorithm {
51  
52      /** {@link org.apache.commons.logging} logging facility */
53      private static java.util.logging.Logger log =
54          java.util.logging.Logger.getLogger(SignatureAlgorithm.class.getName());
55  
56      /** All available algorithm classes are registered here */
57      private static Map<String, Class<? extends SignatureAlgorithmSpi>> algorithmHash =
58          new ConcurrentHashMap<String, Class<? extends SignatureAlgorithmSpi>>();
59  
60      /** Field signatureAlgorithm */
61      private final SignatureAlgorithmSpi signatureAlgorithm;
62  
63      private final String algorithmURI;
64  
65      /**
66       * Constructor SignatureAlgorithm
67       *
68       * @param doc
69       * @param algorithmURI
70       * @throws XMLSecurityException
71       */
72      public SignatureAlgorithm(Document doc, String algorithmURI) throws XMLSecurityException {
73          super(doc, algorithmURI);
74          this.algorithmURI = algorithmURI;
75  
76          signatureAlgorithm = getSignatureAlgorithmSpi(algorithmURI);
77          signatureAlgorithm.engineGetContextFromElement(this.constructionElement);
78      }
79  
80      /**
81       * Constructor SignatureAlgorithm
82       *
83       * @param doc
84       * @param algorithmURI
85       * @param hmacOutputLength
86       * @throws XMLSecurityException
87       */
88      public SignatureAlgorithm(
89          Document doc, String algorithmURI, int hmacOutputLength
90      ) throws XMLSecurityException {
91          super(doc, algorithmURI);
92          this.algorithmURI = algorithmURI;
93  
94          signatureAlgorithm = getSignatureAlgorithmSpi(algorithmURI);
95          signatureAlgorithm.engineGetContextFromElement(this.constructionElement);
96  
97          signatureAlgorithm.engineSetHMACOutputLength(hmacOutputLength);
98          ((IntegrityHmac)signatureAlgorithm).engineAddContextToElement(constructionElement);
99      }
100 
101     /**
102      * Constructor SignatureAlgorithm
103      *
104      * @param element
105      * @param baseURI
106      * @throws XMLSecurityException
107      */
108     public SignatureAlgorithm(Element element, String baseURI) throws XMLSecurityException {
109         this(element, baseURI, false);
110     }
111 
112     /**
113      * Constructor SignatureAlgorithm
114      *
115      * @param element
116      * @param baseURI
117      * @param secureValidation
118      * @throws XMLSecurityException
119      */
120     public SignatureAlgorithm(
121         Element element, String baseURI, boolean secureValidation
122     ) throws XMLSecurityException {
123         super(element, baseURI);
124         algorithmURI = this.getURI();
125 
126         Attr attr = element.getAttributeNodeNS(null, "Id");
127         if (attr != null) {
128             element.setIdAttributeNode(attr, true);
129         }
130 
131         if (secureValidation && (XMLSignature.ALGO_ID_MAC_HMAC_NOT_RECOMMENDED_MD5.equals(algorithmURI)
132             || XMLSignature.ALGO_ID_SIGNATURE_NOT_RECOMMENDED_RSA_MD5.equals(algorithmURI))) {
133             Object exArgs[] = { algorithmURI };
134 
135             throw new XMLSecurityException("signature.signatureAlgorithm", exArgs);
136         }
137 
138         signatureAlgorithm = getSignatureAlgorithmSpi(algorithmURI);
139         signatureAlgorithm.engineGetContextFromElement(this.constructionElement);
140     }
141 
142     /**
143      * Get a SignatureAlgorithmSpi object corresponding to the algorithmURI argument
144      */
145     private static SignatureAlgorithmSpi getSignatureAlgorithmSpi(String algorithmURI)
146         throws XMLSignatureException {
147         try {
148             Class<? extends SignatureAlgorithmSpi> implementingClass =
149                 algorithmHash.get(algorithmURI);
150             if (log.isLoggable(java.util.logging.Level.FINE)) {
151                 log.log(java.util.logging.Level.FINE, "Create URI \"" + algorithmURI + "\" class \""
152                    + implementingClass + "\"");
153             }
154             return implementingClass.newInstance();
155         }  catch (IllegalAccessException ex) {
156             Object exArgs[] = { algorithmURI, ex.getMessage() };
157             throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs, ex);
158         } catch (InstantiationException ex) {
159             Object exArgs[] = { algorithmURI, ex.getMessage() };
160             throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs, ex);
161         } catch (NullPointerException ex) {
162             Object exArgs[] = { algorithmURI, ex.getMessage() };
163             throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs, ex);
164         }
165     }
166 
167 
168     /**
169      * Proxy method for {@link java.security.Signature#sign()}
170      * which is executed on the internal {@link java.security.Signature} object.
171      *
172      * @return the result of the {@link java.security.Signature#sign()} method
173      * @throws XMLSignatureException
174      */
175     public byte[] sign() throws XMLSignatureException {
176         return signatureAlgorithm.engineSign();
177     }
178 
179     /**
180      * Proxy method for {@link java.security.Signature#getAlgorithm}
181      * which is executed on the internal {@link java.security.Signature} object.
182      *
183      * @return the result of the {@link java.security.Signature#getAlgorithm} method
184      */
185     public String getJCEAlgorithmString() {
186         return signatureAlgorithm.engineGetJCEAlgorithmString();
187     }
188 
189     /**
190      * Method getJCEProviderName
191      *
192      * @return The Provider of this Signature Algorithm
193      */
194     public String getJCEProviderName() {
195         return signatureAlgorithm.engineGetJCEProviderName();
196     }
197 
198     /**
199      * Proxy method for {@link java.security.Signature#update(byte[])}
200      * which is executed on the internal {@link java.security.Signature} object.
201      *
202      * @param input
203      * @throws XMLSignatureException
204      */
205     public void update(byte[] input) throws XMLSignatureException {
206         signatureAlgorithm.engineUpdate(input);
207     }
208 
209     /**
210      * Proxy method for {@link java.security.Signature#update(byte)}
211      * which is executed on the internal {@link java.security.Signature} object.
212      *
213      * @param input
214      * @throws XMLSignatureException
215      */
216     public void update(byte input) throws XMLSignatureException {
217         signatureAlgorithm.engineUpdate(input);
218     }
219 
220     /**
221      * Proxy method for {@link java.security.Signature#update(byte[], int, int)}
222      * which is executed on the internal {@link java.security.Signature} object.
223      *
224      * @param buf
225      * @param offset
226      * @param len
227      * @throws XMLSignatureException
228      */
229     public void update(byte buf[], int offset, int len) throws XMLSignatureException {
230         signatureAlgorithm.engineUpdate(buf, offset, len);
231     }
232 
233     /**
234      * Proxy method for {@link java.security.Signature#initSign(java.security.PrivateKey)}
235      * which is executed on the internal {@link java.security.Signature} object.
236      *
237      * @param signingKey
238      * @throws XMLSignatureException
239      */
240     public void initSign(Key signingKey) throws XMLSignatureException {
241         signatureAlgorithm.engineInitSign(signingKey);
242     }
243 
244     /**
245      * Proxy method for {@link java.security.Signature#initSign(java.security.PrivateKey,
246      * java.security.SecureRandom)}
247      * which is executed on the internal {@link java.security.Signature} object.
248      *
249      * @param signingKey
250      * @param secureRandom
251      * @throws XMLSignatureException
252      */
253     public void initSign(Key signingKey, SecureRandom secureRandom) throws XMLSignatureException {
254         signatureAlgorithm.engineInitSign(signingKey, secureRandom);
255     }
256 
257     /**
258      * Proxy method for {@link java.security.Signature#initSign(java.security.PrivateKey)}
259      * which is executed on the internal {@link java.security.Signature} object.
260      *
261      * @param signingKey
262      * @param algorithmParameterSpec
263      * @throws XMLSignatureException
264      */
265     public void initSign(
266         Key signingKey, AlgorithmParameterSpec algorithmParameterSpec
267     ) throws XMLSignatureException {
268         signatureAlgorithm.engineInitSign(signingKey, algorithmParameterSpec);
269     }
270 
271     /**
272      * Proxy method for {@link java.security.Signature#setParameter(
273      * java.security.spec.AlgorithmParameterSpec)}
274      * which is executed on the internal {@link java.security.Signature} object.
275      *
276      * @param params
277      * @throws XMLSignatureException
278      */
279     public void setParameter(AlgorithmParameterSpec params) throws XMLSignatureException {
280         signatureAlgorithm.engineSetParameter(params);
281     }
282 
283     /**
284      * Proxy method for {@link java.security.Signature#initVerify(java.security.PublicKey)}
285      * which is executed on the internal {@link java.security.Signature} object.
286      *
287      * @param verificationKey
288      * @throws XMLSignatureException
289      */
290     public void initVerify(Key verificationKey) throws XMLSignatureException {
291         signatureAlgorithm.engineInitVerify(verificationKey);
292     }
293 
294     /**
295      * Proxy method for {@link java.security.Signature#verify(byte[])}
296      * which is executed on the internal {@link java.security.Signature} object.
297      *
298      * @param signature
299      * @return true if if the signature is valid.
300      *
301      * @throws XMLSignatureException
302      */
303     public boolean verify(byte[] signature) throws XMLSignatureException {
304         return signatureAlgorithm.engineVerify(signature);
305     }
306 
307     /**
308      * Returns the URI representation of Transformation algorithm
309      *
310      * @return the URI representation of Transformation algorithm
311      */
312     public final String getURI() {
313         return constructionElement.getAttributeNS(null, Constants._ATT_ALGORITHM);
314     }
315 
316     /**
317      * Registers implementing class of the Transform algorithm with algorithmURI
318      *
319      * @param algorithmURI algorithmURI URI representation of <code>Transform algorithm</code>.
320      * @param implementingClass <code>implementingClass</code> the implementing class of
321      * {@link SignatureAlgorithmSpi}
322      * @throws AlgorithmAlreadyRegisteredException if specified algorithmURI is already registered
323      * @throws XMLSignatureException
324      */
325     @SuppressWarnings("unchecked")
326     public static void register(String algorithmURI, String implementingClass)
327        throws AlgorithmAlreadyRegisteredException, ClassNotFoundException,
328            XMLSignatureException {
329         if (log.isLoggable(java.util.logging.Level.FINE)) {
330             log.log(java.util.logging.Level.FINE, "Try to register " + algorithmURI + " " + implementingClass);
331         }
332 
333         // are we already registered?
334         Class<? extends SignatureAlgorithmSpi> registeredClass = algorithmHash.get(algorithmURI);
335         if (registeredClass != null) {
336             Object exArgs[] = { algorithmURI, registeredClass };
337             throw new AlgorithmAlreadyRegisteredException(
338                 "algorithm.alreadyRegistered", exArgs
339             );
340         }
341         try {
342             Class<? extends SignatureAlgorithmSpi> clazz =
343                 (Class<? extends SignatureAlgorithmSpi>)
344                     ClassLoaderUtils.loadClass(implementingClass, SignatureAlgorithm.class);
345             algorithmHash.put(algorithmURI, clazz);
346         } catch (NullPointerException ex) {
347             Object exArgs[] = { algorithmURI, ex.getMessage() };
348             throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs, ex);
349         }
350     }
351 
352     /**
353      * Registers implementing class of the Transform algorithm with algorithmURI
354      *
355      * @param algorithmURI algorithmURI URI representation of <code>Transform algorithm</code>.
356      * @param implementingClass <code>implementingClass</code> the implementing class of
357      * {@link SignatureAlgorithmSpi}
358      * @throws AlgorithmAlreadyRegisteredException if specified algorithmURI is already registered
359      * @throws XMLSignatureException
360      */
361     public static void register(String algorithmURI, Class<? extends SignatureAlgorithmSpi> implementingClass)
362        throws AlgorithmAlreadyRegisteredException, ClassNotFoundException,
363            XMLSignatureException {
364         if (log.isLoggable(java.util.logging.Level.FINE)) {
365             log.log(java.util.logging.Level.FINE, "Try to register " + algorithmURI + " " + implementingClass);
366         }
367 
368         // are we already registered?
369         Class<? extends SignatureAlgorithmSpi> registeredClass = algorithmHash.get(algorithmURI);
370         if (registeredClass != null) {
371             Object exArgs[] = { algorithmURI, registeredClass };
372             throw new AlgorithmAlreadyRegisteredException(
373                 "algorithm.alreadyRegistered", exArgs
374             );
375         }
376         algorithmHash.put(algorithmURI, implementingClass);
377     }
378 
379     /**
380      * This method registers the default algorithms.
381      */
382     public static void registerDefaultAlgorithms() {
383         algorithmHash.put(SignatureDSA.URI, SignatureDSA.class);
384         algorithmHash.put(
385             XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1, SignatureBaseRSA.SignatureRSASHA1.class
386         );
387         algorithmHash.put(
388             XMLSignature.ALGO_ID_MAC_HMAC_SHA1, IntegrityHmac.IntegrityHmacSHA1.class
389         );
390         algorithmHash.put(
391             XMLSignature.ALGO_ID_SIGNATURE_NOT_RECOMMENDED_RSA_MD5,
392             SignatureBaseRSA.SignatureRSAMD5.class
393         );
394         algorithmHash.put(
395             XMLSignature.ALGO_ID_SIGNATURE_RSA_RIPEMD160,
396             SignatureBaseRSA.SignatureRSARIPEMD160.class
397         );
398         algorithmHash.put(
399             XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256, SignatureBaseRSA.SignatureRSASHA256.class
400         );
401         algorithmHash.put(
402             XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384, SignatureBaseRSA.SignatureRSASHA384.class
403         );
404         algorithmHash.put(
405             XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512, SignatureBaseRSA.SignatureRSASHA512.class
406         );
407         algorithmHash.put(
408             XMLSignature.ALGO_ID_SIGNATURE_ECDSA_SHA1, SignatureECDSA.SignatureECDSASHA1.class
409         );
410         algorithmHash.put(
411             XMLSignature.ALGO_ID_SIGNATURE_ECDSA_SHA256, SignatureECDSA.SignatureECDSASHA256.class
412         );
413         algorithmHash.put(
414             XMLSignature.ALGO_ID_SIGNATURE_ECDSA_SHA384, SignatureECDSA.SignatureECDSASHA384.class
415         );
416         algorithmHash.put(
417             XMLSignature.ALGO_ID_SIGNATURE_ECDSA_SHA512, SignatureECDSA.SignatureECDSASHA512.class
418         );
419         algorithmHash.put(
420             XMLSignature.ALGO_ID_MAC_HMAC_NOT_RECOMMENDED_MD5, IntegrityHmac.IntegrityHmacMD5.class
421         );
422         algorithmHash.put(
423             XMLSignature.ALGO_ID_MAC_HMAC_RIPEMD160, IntegrityHmac.IntegrityHmacRIPEMD160.class
424         );
425         algorithmHash.put(
426             XMLSignature.ALGO_ID_MAC_HMAC_SHA256, IntegrityHmac.IntegrityHmacSHA256.class
427         );
428         algorithmHash.put(
429             XMLSignature.ALGO_ID_MAC_HMAC_SHA384, IntegrityHmac.IntegrityHmacSHA384.class
430         );
431         algorithmHash.put(
432             XMLSignature.ALGO_ID_MAC_HMAC_SHA512, IntegrityHmac.IntegrityHmacSHA512.class
433         );
434     }
435 
436     /**
437      * Method getBaseNamespace
438      *
439      * @return URI of this element
440      */
441     public String getBaseNamespace() {
442         return Constants.SignatureSpecNS;
443     }
444 
445     /**
446      * Method getBaseLocalName
447      *
448      * @return Local name
449      */
450     public String getBaseLocalName() {
451         return Constants._TAG_SIGNATUREMETHOD;
452     }
453 }