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             @SuppressWarnings("deprecation")
 156             SignatureAlgorithmSpi result = implementingClass.newInstance();
 157             return result;
 158         }  catch (IllegalAccessException ex) {
 159             Object exArgs[] = { algorithmURI, ex.getMessage() };
 160             throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs, ex);
 161         } catch (InstantiationException ex) {
 162             Object exArgs[] = { algorithmURI, ex.getMessage() };
 163             throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs, ex);
 164         } catch (NullPointerException ex) {
 165             Object exArgs[] = { algorithmURI, ex.getMessage() };
 166             throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs, ex);
 167         }
 168     }
 169 
 170 
 171     /**
 172      * Proxy method for {@link java.security.Signature#sign()}
 173      * which is executed on the internal {@link java.security.Signature} object.
 174      *
 175      * @return the result of the {@link java.security.Signature#sign()} method
 176      * @throws XMLSignatureException
 177      */
 178     public byte[] sign() throws XMLSignatureException {
 179         return signatureAlgorithm.engineSign();
 180     }
 181 
 182     /**
 183      * Proxy method for {@link java.security.Signature#getAlgorithm}
 184      * which is executed on the internal {@link java.security.Signature} object.
 185      *
 186      * @return the result of the {@link java.security.Signature#getAlgorithm} method
 187      */
 188     public String getJCEAlgorithmString() {
 189         return signatureAlgorithm.engineGetJCEAlgorithmString();
 190     }
 191 
 192     /**
 193      * Method getJCEProviderName
 194      *
 195      * @return The Provider of this Signature Algorithm
 196      */
 197     public String getJCEProviderName() {
 198         return signatureAlgorithm.engineGetJCEProviderName();
 199     }
 200 
 201     /**
 202      * Proxy method for {@link java.security.Signature#update(byte[])}
 203      * which is executed on the internal {@link java.security.Signature} object.
 204      *
 205      * @param input
 206      * @throws XMLSignatureException
 207      */
 208     public void update(byte[] input) throws XMLSignatureException {
 209         signatureAlgorithm.engineUpdate(input);
 210     }
 211 
 212     /**
 213      * Proxy method for {@link java.security.Signature#update(byte)}
 214      * which is executed on the internal {@link java.security.Signature} object.
 215      *
 216      * @param input
 217      * @throws XMLSignatureException
 218      */
 219     public void update(byte input) throws XMLSignatureException {
 220         signatureAlgorithm.engineUpdate(input);
 221     }
 222 
 223     /**
 224      * Proxy method for {@link java.security.Signature#update(byte[], int, int)}
 225      * which is executed on the internal {@link java.security.Signature} object.
 226      *
 227      * @param buf
 228      * @param offset
 229      * @param len
 230      * @throws XMLSignatureException
 231      */
 232     public void update(byte buf[], int offset, int len) throws XMLSignatureException {
 233         signatureAlgorithm.engineUpdate(buf, offset, len);
 234     }
 235 
 236     /**
 237      * Proxy method for {@link java.security.Signature#initSign(java.security.PrivateKey)}
 238      * which is executed on the internal {@link java.security.Signature} object.
 239      *
 240      * @param signingKey
 241      * @throws XMLSignatureException
 242      */
 243     public void initSign(Key signingKey) throws XMLSignatureException {
 244         signatureAlgorithm.engineInitSign(signingKey);
 245     }
 246 
 247     /**
 248      * Proxy method for {@link java.security.Signature#initSign(java.security.PrivateKey,
 249      * java.security.SecureRandom)}
 250      * which is executed on the internal {@link java.security.Signature} object.
 251      *
 252      * @param signingKey
 253      * @param secureRandom
 254      * @throws XMLSignatureException
 255      */
 256     public void initSign(Key signingKey, SecureRandom secureRandom) throws XMLSignatureException {
 257         signatureAlgorithm.engineInitSign(signingKey, secureRandom);
 258     }
 259 
 260     /**
 261      * Proxy method for {@link java.security.Signature#initSign(java.security.PrivateKey)}
 262      * which is executed on the internal {@link java.security.Signature} object.
 263      *
 264      * @param signingKey
 265      * @param algorithmParameterSpec
 266      * @throws XMLSignatureException
 267      */
 268     public void initSign(
 269         Key signingKey, AlgorithmParameterSpec algorithmParameterSpec
 270     ) throws XMLSignatureException {
 271         signatureAlgorithm.engineInitSign(signingKey, algorithmParameterSpec);
 272     }
 273 
 274     /**
 275      * Proxy method for {@link java.security.Signature#setParameter(
 276      * java.security.spec.AlgorithmParameterSpec)}
 277      * which is executed on the internal {@link java.security.Signature} object.
 278      *
 279      * @param params
 280      * @throws XMLSignatureException
 281      */
 282     public void setParameter(AlgorithmParameterSpec params) throws XMLSignatureException {
 283         signatureAlgorithm.engineSetParameter(params);
 284     }
 285 
 286     /**
 287      * Proxy method for {@link java.security.Signature#initVerify(java.security.PublicKey)}
 288      * which is executed on the internal {@link java.security.Signature} object.
 289      *
 290      * @param verificationKey
 291      * @throws XMLSignatureException
 292      */
 293     public void initVerify(Key verificationKey) throws XMLSignatureException {
 294         signatureAlgorithm.engineInitVerify(verificationKey);
 295     }
 296 
 297     /**
 298      * Proxy method for {@link java.security.Signature#verify(byte[])}
 299      * which is executed on the internal {@link java.security.Signature} object.
 300      *
 301      * @param signature
 302      * @return true if the signature is valid.
 303      *
 304      * @throws XMLSignatureException
 305      */
 306     public boolean verify(byte[] signature) throws XMLSignatureException {
 307         return signatureAlgorithm.engineVerify(signature);
 308     }
 309 
 310     /**
 311      * Returns the URI representation of Transformation algorithm
 312      *
 313      * @return the URI representation of Transformation algorithm
 314      */
 315     public final String getURI() {
 316         return constructionElement.getAttributeNS(null, Constants._ATT_ALGORITHM);
 317     }
 318 
 319     /**
 320      * Registers implementing class of the SignatureAlgorithm with algorithmURI
 321      *
 322      * @param algorithmURI algorithmURI URI representation of <code>SignatureAlgorithm</code>.
 323      * @param implementingClass <code>implementingClass</code> the implementing class of
 324      * {@link SignatureAlgorithmSpi}
 325      * @throws AlgorithmAlreadyRegisteredException if specified algorithmURI is already registered
 326      * @throws XMLSignatureException
 327      * @throws SecurityException if a security manager is installed and the
 328      *    caller does not have permission to register the signature algorithm
 329      */
 330     @SuppressWarnings("unchecked")
 331     public static void register(String algorithmURI, String implementingClass)
 332        throws AlgorithmAlreadyRegisteredException, ClassNotFoundException,
 333            XMLSignatureException {
 334         JavaUtils.checkRegisterPermission();
 335         if (log.isLoggable(java.util.logging.Level.FINE)) {
 336             log.log(java.util.logging.Level.FINE, "Try to register " + algorithmURI + " " + implementingClass);
 337         }
 338 
 339         // are we already registered?
 340         Class<? extends SignatureAlgorithmSpi> registeredClass = algorithmHash.get(algorithmURI);
 341         if (registeredClass != null) {
 342             Object exArgs[] = { algorithmURI, registeredClass };
 343             throw new AlgorithmAlreadyRegisteredException(
 344                 "algorithm.alreadyRegistered", exArgs
 345             );
 346         }
 347         try {
 348             Class<? extends SignatureAlgorithmSpi> clazz =
 349                 (Class<? extends SignatureAlgorithmSpi>)
 350                     ClassLoaderUtils.loadClass(implementingClass, SignatureAlgorithm.class);
 351             algorithmHash.put(algorithmURI, clazz);
 352         } catch (NullPointerException ex) {
 353             Object exArgs[] = { algorithmURI, ex.getMessage() };
 354             throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs, ex);
 355         }
 356     }
 357 
 358     /**
 359      * Registers implementing class of the Transform algorithm with algorithmURI
 360      *
 361      * @param algorithmURI algorithmURI URI representation of <code>SignatureAlgorithm</code>.
 362      * @param implementingClass <code>implementingClass</code> the implementing class of
 363      * {@link SignatureAlgorithmSpi}
 364      * @throws AlgorithmAlreadyRegisteredException if specified algorithmURI is already registered
 365      * @throws XMLSignatureException
 366      * @throws SecurityException if a security manager is installed and the
 367      *    caller does not have permission to register the signature algorithm
 368      */
 369     public static void register(String algorithmURI, Class<? extends SignatureAlgorithmSpi> implementingClass)
 370        throws AlgorithmAlreadyRegisteredException, ClassNotFoundException,
 371            XMLSignatureException {
 372         JavaUtils.checkRegisterPermission();
 373         if (log.isLoggable(java.util.logging.Level.FINE)) {
 374             log.log(java.util.logging.Level.FINE, "Try to register " + algorithmURI + " " + implementingClass);
 375         }
 376 
 377         // are we already registered?
 378         Class<? extends SignatureAlgorithmSpi> registeredClass = algorithmHash.get(algorithmURI);
 379         if (registeredClass != null) {
 380             Object exArgs[] = { algorithmURI, registeredClass };
 381             throw new AlgorithmAlreadyRegisteredException(
 382                 "algorithm.alreadyRegistered", exArgs
 383             );
 384         }
 385         algorithmHash.put(algorithmURI, implementingClass);
 386     }
 387 
 388     /**
 389      * This method registers the default algorithms.
 390      */
 391     public static void registerDefaultAlgorithms() {
 392         algorithmHash.put(
 393             XMLSignature.ALGO_ID_SIGNATURE_DSA, SignatureDSA.class
 394         );
 395         algorithmHash.put(
 396             XMLSignature.ALGO_ID_SIGNATURE_DSA_SHA256, SignatureDSA.SHA256.class
 397         );
 398         algorithmHash.put(
 399             XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1, SignatureBaseRSA.SignatureRSASHA1.class
 400         );
 401         algorithmHash.put(
 402             XMLSignature.ALGO_ID_MAC_HMAC_SHA1, IntegrityHmac.IntegrityHmacSHA1.class
 403         );
 404         algorithmHash.put(
 405             XMLSignature.ALGO_ID_SIGNATURE_NOT_RECOMMENDED_RSA_MD5,
 406             SignatureBaseRSA.SignatureRSAMD5.class
 407         );
 408         algorithmHash.put(
 409             XMLSignature.ALGO_ID_SIGNATURE_RSA_RIPEMD160,
 410             SignatureBaseRSA.SignatureRSARIPEMD160.class
 411         );
 412         algorithmHash.put(
 413             XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256, SignatureBaseRSA.SignatureRSASHA256.class
 414         );
 415         algorithmHash.put(
 416             XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384, SignatureBaseRSA.SignatureRSASHA384.class
 417         );
 418         algorithmHash.put(
 419             XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512, SignatureBaseRSA.SignatureRSASHA512.class
 420         );
 421         algorithmHash.put(
 422             XMLSignature.ALGO_ID_SIGNATURE_ECDSA_SHA1, SignatureECDSA.SignatureECDSASHA1.class
 423         );
 424         algorithmHash.put(
 425             XMLSignature.ALGO_ID_SIGNATURE_ECDSA_SHA256, SignatureECDSA.SignatureECDSASHA256.class
 426         );
 427         algorithmHash.put(
 428             XMLSignature.ALGO_ID_SIGNATURE_ECDSA_SHA384, SignatureECDSA.SignatureECDSASHA384.class
 429         );
 430         algorithmHash.put(
 431             XMLSignature.ALGO_ID_SIGNATURE_ECDSA_SHA512, SignatureECDSA.SignatureECDSASHA512.class
 432         );
 433         algorithmHash.put(
 434             XMLSignature.ALGO_ID_MAC_HMAC_NOT_RECOMMENDED_MD5, IntegrityHmac.IntegrityHmacMD5.class
 435         );
 436         algorithmHash.put(
 437             XMLSignature.ALGO_ID_MAC_HMAC_RIPEMD160, IntegrityHmac.IntegrityHmacRIPEMD160.class
 438         );
 439         algorithmHash.put(
 440             XMLSignature.ALGO_ID_MAC_HMAC_SHA256, IntegrityHmac.IntegrityHmacSHA256.class
 441         );
 442         algorithmHash.put(
 443             XMLSignature.ALGO_ID_MAC_HMAC_SHA384, IntegrityHmac.IntegrityHmacSHA384.class
 444         );
 445         algorithmHash.put(
 446             XMLSignature.ALGO_ID_MAC_HMAC_SHA512, IntegrityHmac.IntegrityHmacSHA512.class
 447         );
 448     }
 449 
 450     /**
 451      * Method getBaseNamespace
 452      *
 453      * @return URI of this element
 454      */
 455     public String getBaseNamespace() {
 456         return Constants.SignatureSpecNS;
 457     }
 458 
 459     /**
 460      * Method getBaseLocalName
 461      *
 462      * @return Local name
 463      */
 464     public String getBaseLocalName() {
 465         return Constants._TAG_SIGNATUREMETHOD;
 466     }
 467 }