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 }