1 /*
   2  * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 /*
  26  * $Id: TransformService.java,v 1.6.4.1 2005/09/15 12:42:11 mullan Exp $
  27  */
  28 package javax.xml.crypto.dsig;
  29 
  30 import java.security.InvalidAlgorithmParameterException;
  31 import java.security.NoSuchAlgorithmException;
  32 import java.security.NoSuchProviderException;
  33 import java.security.Provider;
  34 import java.security.Provider.Service;
  35 import java.security.Security;
  36 import java.util.*;
  37 import javax.xml.crypto.MarshalException;
  38 import javax.xml.crypto.XMLStructure;
  39 import javax.xml.crypto.XMLCryptoContext;
  40 import javax.xml.crypto.dsig.spec.TransformParameterSpec;
  41 
  42 import sun.security.jca.*;
  43 import sun.security.jca.GetInstance.Instance;
  44 
  45 /**
  46  * A Service Provider Interface for transform and canonicalization algorithms.
  47  *
  48  * <p>Each instance of <code>TransformService</code> supports a specific
  49  * transform or canonicalization algorithm and XML mechanism type. To create a
  50  * <code>TransformService</code>, call one of the static
  51  * {@link #getInstance getInstance} methods, passing in the algorithm URI and
  52  * XML mechanism type desired, for example:
  53  *
  54  * <blockquote><code>
  55  * TransformService ts = TransformService.getInstance(Transform.XPATH2, "DOM");
  56  * </code></blockquote>
  57  *
  58  * <p><code>TransformService</code> implementations are registered and loaded
  59  * using the {@link java.security.Provider} mechanism.  Each
  60  * <code>TransformService</code> service provider implementation should include
  61  * a <code>MechanismType</code> service attribute that identifies the XML
  62  * mechanism type that it supports. If the attribute is not specified,
  63  * "DOM" is assumed. For example, a service provider that supports the
  64  * XPath Filter 2 Transform and DOM mechanism would be specified in the
  65  * <code>Provider</code> subclass as:
  66  * <pre>
  67  *     put("TransformService." + Transform.XPATH2,
  68  *         "org.example.XPath2TransformService");
  69  *     put("TransformService." + Transform.XPATH2 + " MechanismType", "DOM");
  70  * </pre>
  71  * <code>TransformService</code> implementations that support the DOM
  72  * mechanism type must abide by the DOM interoperability requirements defined
  73  * in the
  74  * <a href="../../../../../technotes/guides/security/xmldsig/overview.html#DOM%20Mechanism%20Requirements">
  75  * DOM Mechanism Requirements</a> section of the API overview. See the
  76  * <a href="../../../../../technotes/guides/security/xmldsig/overview.html#Service%20Provider">
  77  * Service Providers</a> section of the API overview for a list of standard
  78  * mechanism types.
  79  * <p>
  80  * Once a <code>TransformService</code> has been created, it can be used
  81  * to process <code>Transform</code> or <code>CanonicalizationMethod</code>
  82  * objects. If the <code>Transform</code> or <code>CanonicalizationMethod</code>
  83  * exists in XML form (for example, when validating an existing
  84  * <code>XMLSignature</code>), the {@link #init(XMLStructure, XMLCryptoContext)}
  85  * method must be first called to initialize the transform and provide document
  86  * context (even if there are no parameters). Alternatively, if the
  87  * <code>Transform</code> or <code>CanonicalizationMethod</code> is being
  88  * created from scratch, the {@link #init(TransformParameterSpec)} method
  89  * is called to initialize the transform with parameters and the
  90  * {@link #marshalParams marshalParams} method is called to marshal the
  91  * parameters to XML and provide the transform with document context. Finally,
  92  * the {@link #transform transform} method is called to perform the
  93  * transformation.
  94  * <p>
  95  * <b>Concurrent Access</b>
  96  * <p>The static methods of this class are guaranteed to be thread-safe.
  97  * Multiple threads may concurrently invoke the static methods defined in this
  98  * class with no ill effects.
  99  *
 100  * <p>However, this is not true for the non-static methods defined by this
 101  * class. Unless otherwise documented by a specific provider, threads that
 102  * need to access a single <code>TransformService</code> instance
 103  * concurrently should synchronize amongst themselves and provide the
 104  * necessary locking. Multiple threads each manipulating a different
 105  * <code>TransformService</code> instance need not synchronize.
 106  *
 107  * @author Sean Mullan
 108  * @author JSR 105 Expert Group
 109  * @since 1.6
 110  */
 111 public abstract class TransformService implements Transform {
 112 
 113     private String algorithm;
 114     private String mechanism;
 115     private Provider provider;
 116 
 117     /**
 118      * Default constructor, for invocation by subclasses.
 119      */
 120     protected TransformService() {}
 121 
 122     /**
 123      * Returns a <code>TransformService</code> that supports the specified
 124      * algorithm URI (ex: {@link Transform#XPATH2}) and mechanism type
 125      * (ex: DOM).
 126      *
 127      * <p>This method uses the standard JCA provider lookup mechanism to
 128      * locate and instantiate a <code>TransformService</code> implementation
 129      * of the desired algorithm and <code>MechanismType</code> service
 130      * attribute. It traverses the list of registered security
 131      * <code>Provider</code>s, starting with the most preferred
 132      * <code>Provider</code>. A new <code>TransformService</code> object
 133      * from the first <code>Provider</code> that supports the specified
 134      * algorithm and mechanism type is returned.
 135      *
 136      * <p> Note that the list of registered providers may be retrieved via
 137      * the {@link Security#getProviders() Security.getProviders()} method.
 138      *
 139      * @implNote
 140      * The JDK Reference Implementation additionally uses the
 141      * {@code jdk.security.provider.preferred}
 142      * {@link Security#getProperty(String) Security} property to determine
 143      * the preferred provider order for the specified algorithm. This
 144      * may be different than the order of providers returned by
 145      * {@link Security#getProviders() Security.getProviders()}.
 146      *
 147      * @param algorithm the URI of the algorithm
 148      * @param mechanismType the type of the XML processing mechanism and
 149      *   representation
 150      * @return a new <code>TransformService</code>
 151      * @throws NullPointerException if <code>algorithm</code> or
 152      *   <code>mechanismType</code> is  <code>null</code>
 153      * @throws NoSuchAlgorithmException if no <code>Provider</code> supports a
 154      *   <code>TransformService</code> implementation for the specified
 155      *   algorithm and mechanism type
 156      * @see Provider
 157      */
 158     public static TransformService getInstance
 159         (String algorithm, String mechanismType)
 160         throws NoSuchAlgorithmException {
 161         if (mechanismType == null || algorithm == null) {
 162             throw new NullPointerException();
 163         }
 164         boolean dom = false;
 165         if (mechanismType.equals("DOM")) {
 166             dom = true;
 167         }
 168         List<Service> services = GetInstance.getServices("TransformService", algorithm);
 169         for (Iterator<Service> t = services.iterator(); t.hasNext(); ) {
 170             Service s = t.next();
 171             String value = s.getAttribute("MechanismType");
 172             if ((value == null && dom) ||
 173                 (value != null && value.equals(mechanismType))) {
 174                 Instance instance = GetInstance.getInstance(s, null);
 175                 TransformService ts = (TransformService) instance.impl;
 176                 ts.algorithm = algorithm;
 177                 ts.mechanism = mechanismType;
 178                 ts.provider = instance.provider;
 179                 return ts;
 180             }
 181         }
 182         throw new NoSuchAlgorithmException
 183             (algorithm + " algorithm and " + mechanismType
 184                  + " mechanism not available");
 185     }
 186 
 187     /**
 188      * Returns a <code>TransformService</code> that supports the specified
 189      * algorithm URI (ex: {@link Transform#XPATH2}) and mechanism type
 190      * (ex: DOM) as supplied by the specified provider. Note that the specified
 191      * <code>Provider</code> object does not have to be registered in the
 192      * provider list.
 193      *
 194      * @param algorithm the URI of the algorithm
 195      * @param mechanismType the type of the XML processing mechanism and
 196      *   representation
 197      * @param provider the <code>Provider</code> object
 198      * @return a new <code>TransformService</code>
 199      * @throws NullPointerException if <code>provider</code>,
 200      *   <code>algorithm</code>, or <code>mechanismType</code> is
 201      *   <code>null</code>
 202      * @throws NoSuchAlgorithmException if a <code>TransformService</code>
 203      *   implementation for the specified algorithm and mechanism type is not
 204      *   available from the specified <code>Provider</code> object
 205      * @see Provider
 206      */
 207     public static TransformService getInstance
 208         (String algorithm, String mechanismType, Provider provider)
 209         throws NoSuchAlgorithmException {
 210         if (mechanismType == null || algorithm == null || provider == null) {
 211             throw new NullPointerException();
 212         }
 213 
 214         boolean dom = false;
 215         if (mechanismType.equals("DOM")) {
 216             dom = true;
 217         }
 218         Service s = GetInstance.getService
 219             ("TransformService", algorithm, provider);
 220         String value = s.getAttribute("MechanismType");
 221         if ((value == null && dom) ||
 222             (value != null && value.equals(mechanismType))) {
 223             Instance instance = GetInstance.getInstance(s, null);
 224             TransformService ts = (TransformService) instance.impl;
 225             ts.algorithm = algorithm;
 226             ts.mechanism = mechanismType;
 227             ts.provider = instance.provider;
 228             return ts;
 229         }
 230         throw new NoSuchAlgorithmException
 231             (algorithm + " algorithm and " + mechanismType
 232                  + " mechanism not available");
 233     }
 234 
 235     /**
 236      * Returns a <code>TransformService</code> that supports the specified
 237      * algorithm URI (ex: {@link Transform#XPATH2}) and mechanism type
 238      * (ex: DOM) as supplied by the specified provider. The specified provider
 239      * must be registered in the security provider list.
 240      *
 241      * <p>Note that the list of registered providers may be retrieved via
 242      * the {@link Security#getProviders() Security.getProviders()} method.
 243      *
 244      * @param algorithm the URI of the algorithm
 245      * @param mechanismType the type of the XML processing mechanism and
 246      *   representation
 247      * @param provider the string name of the provider
 248      * @return a new <code>TransformService</code>
 249      * @throws NoSuchProviderException if the specified provider is not
 250      *   registered in the security provider list
 251      * @throws NullPointerException if <code>provider</code>,
 252      *   <code>mechanismType</code>, or <code>algorithm</code> is
 253      *   <code>null</code>
 254      * @throws NoSuchAlgorithmException if a <code>TransformService</code>
 255      *   implementation for the specified algorithm and mechanism type is not
 256      *   available from the specified provider
 257      * @see Provider
 258      */
 259     public static TransformService getInstance
 260         (String algorithm, String mechanismType, String provider)
 261         throws NoSuchAlgorithmException, NoSuchProviderException {
 262         if (mechanismType == null || algorithm == null || provider == null) {
 263             throw new NullPointerException();
 264         } else if (provider.length() == 0) {
 265             throw new NoSuchProviderException();
 266         }
 267         boolean dom = false;
 268         if (mechanismType.equals("DOM")) {
 269             dom = true;
 270         }
 271         Service s = GetInstance.getService
 272             ("TransformService", algorithm, provider);
 273         String value = s.getAttribute("MechanismType");
 274         if ((value == null && dom) ||
 275             (value != null && value.equals(mechanismType))) {
 276             Instance instance = GetInstance.getInstance(s, null);
 277             TransformService ts = (TransformService) instance.impl;
 278             ts.algorithm = algorithm;
 279             ts.mechanism = mechanismType;
 280             ts.provider = instance.provider;
 281             return ts;
 282         }
 283         throw new NoSuchAlgorithmException
 284             (algorithm + " algorithm and " + mechanismType
 285                  + " mechanism not available");
 286     }
 287 
 288     private static class MechanismMapEntry implements Map.Entry<String,String> {
 289         private final String mechanism;
 290         private final String algorithm;
 291         private final String key;
 292         MechanismMapEntry(String algorithm, String mechanism) {
 293             this.algorithm = algorithm;
 294             this.mechanism = mechanism;
 295             this.key = "TransformService." + algorithm + " MechanismType";
 296         }
 297         public boolean equals(Object o) {
 298             if (!(o instanceof Map.Entry)) {
 299                 return false;
 300             }
 301             Map.Entry<?,?> e = (Map.Entry<?,?>) o;
 302             return (getKey()==null ?
 303                     e.getKey()==null : getKey().equals(e.getKey())) &&
 304                    (getValue()==null ?
 305                     e.getValue()==null : getValue().equals(e.getValue()));
 306         }
 307         public String getKey() {
 308             return key;
 309         }
 310         public String getValue() {
 311             return mechanism;
 312         }
 313         public String setValue(String value) {
 314             throw new UnsupportedOperationException();
 315         }
 316         public int hashCode() {
 317             return (getKey()==null ? 0 : getKey().hashCode()) ^
 318                    (getValue()==null ? 0 : getValue().hashCode());
 319         }
 320     }
 321 
 322     /**
 323      * Returns the mechanism type supported by this <code>TransformService</code>.
 324      *
 325      * @return the mechanism type
 326      */
 327     public final String getMechanismType() {
 328         return mechanism;
 329     }
 330 
 331     /**
 332      * Returns the URI of the algorithm supported by this
 333      * <code>TransformService</code>.
 334      *
 335      * @return the algorithm URI
 336      */
 337     public final String getAlgorithm() {
 338         return algorithm;
 339     }
 340 
 341     /**
 342      * Returns the provider of this <code>TransformService</code>.
 343      *
 344      * @return the provider
 345      */
 346     public final Provider getProvider() {
 347         return provider;
 348     }
 349 
 350     /**
 351      * Initializes this <code>TransformService</code> with the specified
 352      * parameters.
 353      *
 354      * <p>If the parameters exist in XML form, the
 355      * {@link #init(XMLStructure, XMLCryptoContext)} method should be used to
 356      * initialize the <code>TransformService</code>.
 357      *
 358      * @param params the algorithm parameters (may be <code>null</code> if
 359      *   not required or optional)
 360      * @throws InvalidAlgorithmParameterException if the specified parameters
 361      *   are invalid for this algorithm
 362      */
 363     public abstract void init(TransformParameterSpec params)
 364         throws InvalidAlgorithmParameterException;
 365 
 366     /**
 367      * Marshals the algorithm-specific parameters. If there are no parameters
 368      * to be marshalled, this method returns without throwing an exception.
 369      *
 370      * @param parent a mechanism-specific structure containing the parent
 371      *    node that the marshalled parameters should be appended to
 372      * @param context the <code>XMLCryptoContext</code> containing
 373      *    additional context (may be <code>null</code> if not applicable)
 374      * @throws ClassCastException if the type of <code>parent</code> or
 375      *    <code>context</code> is not compatible with this
 376      *    <code>TransformService</code>
 377      * @throws NullPointerException if <code>parent</code> is <code>null</code>
 378      * @throws MarshalException if the parameters cannot be marshalled
 379      */
 380     public abstract void marshalParams
 381         (XMLStructure parent, XMLCryptoContext context)
 382         throws MarshalException;
 383 
 384     /**
 385      * Initializes this <code>TransformService</code> with the specified
 386      * parameters and document context.
 387      *
 388      * @param parent a mechanism-specific structure containing the parent
 389      *    structure
 390      * @param context the <code>XMLCryptoContext</code> containing
 391      *    additional context (may be <code>null</code> if not applicable)
 392      * @throws ClassCastException if the type of <code>parent</code> or
 393      *    <code>context</code> is not compatible with this
 394      *    <code>TransformService</code>
 395      * @throws NullPointerException if <code>parent</code> is <code>null</code>
 396      * @throws InvalidAlgorithmParameterException if the specified parameters
 397      *   are invalid for this algorithm
 398      */
 399     public abstract void init(XMLStructure parent, XMLCryptoContext context)
 400         throws InvalidAlgorithmParameterException;
 401 }