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