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 }