1 /* 2 * Copyright (c) 2005, 2019, 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 43 /** 44 * A Service Provider Interface for transform and canonicalization algorithms. 45 * 46 * <p>Each instance of <code>TransformService</code> supports a specific 47 * transform or canonicalization algorithm and XML mechanism type. To create a 48 * <code>TransformService</code>, call one of the static 49 * {@link #getInstance getInstance} methods, passing in the algorithm URI and 50 * XML mechanism type desired, for example: 51 * 52 * <blockquote><code> 53 * TransformService ts = TransformService.getInstance(Transform.XPATH2, "DOM"); 54 * </code></blockquote> 55 * 56 * <p><code>TransformService</code> implementations are registered and loaded 57 * using the {@link java.security.Provider} mechanism. Each 58 * <code>TransformService</code> service provider implementation should include 59 * a <code>MechanismType</code> service attribute that identifies the XML 60 * mechanism type that it supports. If the attribute is not specified, 61 * "DOM" is assumed. For example, a service provider that supports the 62 * XPath Filter 2 Transform and DOM mechanism would be specified in the 63 * <code>Provider</code> subclass as: 64 * <pre> 65 * put("TransformService." + Transform.XPATH2, 66 * "org.example.XPath2TransformService"); 67 * put("TransformService." + Transform.XPATH2 + " MechanismType", "DOM"); 68 * </pre> 69 * <code>TransformService</code> implementations that support the DOM 70 * mechanism type must abide by the DOM interoperability requirements defined 71 * in the <a href="package-summary.html#dom_req">DOM Mechanism 72 * Requirements</a>. See the {@code TransformService} section in the <a href= 73 * "{@docRoot}/../specs/security/standard-names.html#xml-signature-xmlsignaturefactorykeyinfofactorytransformservice-mechanisms"> 74 * Java Security Standard Algorithm Names Specification</a> for a list of 75 * standard algorithm URIs and mechanism types. 76 * <p> 77 * Once a <code>TransformService</code> has been created, it can be used 78 * to process <code>Transform</code> or <code>CanonicalizationMethod</code> 79 * objects. If the <code>Transform</code> or <code>CanonicalizationMethod</code> 80 * exists in XML form (for example, when validating an existing 81 * <code>XMLSignature</code>), the {@link #init(XMLStructure, XMLCryptoContext)} 82 * method must be first called to initialize the transform and provide document 83 * context (even if there are no parameters). Alternatively, if the 84 * <code>Transform</code> or <code>CanonicalizationMethod</code> is being 85 * created from scratch, the {@link #init(TransformParameterSpec)} method 86 * is called to initialize the transform with parameters and the 87 * {@link #marshalParams marshalParams} method is called to marshal the 88 * parameters to XML and provide the transform with document context. Finally, 89 * the {@link #transform transform} method is called to perform the 90 * transformation. 91 * <p> 92 * <b>Concurrent Access</b> 93 * <p>The static methods of this class are guaranteed to be thread-safe. 94 * Multiple threads may concurrently invoke the static methods defined in this 95 * class with no ill effects. 96 * 97 * <p>However, this is not true for the non-static methods defined by this 98 * class. Unless otherwise documented by a specific provider, threads that 99 * need to access a single <code>TransformService</code> instance 100 * concurrently should synchronize amongst themselves and provide the 101 * necessary locking. Multiple threads each manipulating a different 102 * <code>TransformService</code> instance need not synchronize. 103 * 104 * @author Sean Mullan 105 * @author JSR 105 Expert Group 106 * @since 1.6 107 */ 108 public abstract class TransformService implements Transform { 109 110 private String algorithm; 111 private String mechanism; 112 private Provider provider; 113 114 /** 115 * Default constructor, for invocation by subclasses. 116 */ TransformService()117 protected TransformService() {} 118 119 /** 120 * Returns a <code>TransformService</code> that supports the specified 121 * algorithm URI (ex: {@link Transform#XPATH2}) and mechanism type 122 * (ex: DOM). 123 * 124 * <p>This method uses the standard JCA provider lookup mechanism to 125 * locate and instantiate a <code>TransformService</code> implementation 126 * of the desired algorithm and <code>MechanismType</code> service 127 * attribute. It traverses the list of registered security 128 * <code>Provider</code>s, starting with the most preferred 129 * <code>Provider</code>. A new <code>TransformService</code> object 130 * from the first <code>Provider</code> that supports the specified 131 * algorithm and mechanism type is returned. 132 * 133 * <p> Note that the list of registered providers may be retrieved via 134 * the {@link Security#getProviders() Security.getProviders()} method. 135 * 136 * @implNote 137 * The JDK Reference Implementation additionally uses the 138 * {@code jdk.security.provider.preferred} 139 * {@link Security#getProperty(String) Security} property to determine 140 * the preferred provider order for the specified algorithm. This 141 * may be different than the order of providers returned by 142 * {@link Security#getProviders() Security.getProviders()}. 143 * 144 * @param algorithm the URI of the algorithm. See the 145 * {@code TransformService} section in the 146 * <a href= 147 * "{@docRoot}/../specs/security/standard-names.html#xml-signature-transform-transformservice-algorithms"> 148 * Java Security Standard Algorithm Names Specification</a> for a list of 149 * standard transform algorithms. 150 * @param mechanismType the type of the XML processing mechanism and 151 * representation. See the {@code TransformService} section in the 152 * <a href= 153 * "{@docRoot}/../specs/security/standard-names.html#xml-signature-xmlsignaturefactorykeyinfofactorytransformservice-mechanisms"> 154 * Java Security Standard Algorithm Names Specification</a> for a list of 155 * standard mechanism types. 156 * @return a new <code>TransformService</code> 157 * @throws NullPointerException if <code>algorithm</code> or 158 * <code>mechanismType</code> is <code>null</code> 159 * @throws NoSuchAlgorithmException if no <code>Provider</code> supports a 160 * <code>TransformService</code> implementation for the specified 161 * algorithm and mechanism type 162 * @see Provider 163 */ getInstance(String algorithm, String mechanismType)164 public static TransformService getInstance 165 (String algorithm, String mechanismType) 166 throws NoSuchAlgorithmException { 167 if (mechanismType == null || algorithm == null) { 168 throw new NullPointerException(); 169 } 170 boolean dom = false; 171 if (mechanismType.equals("DOM")) { 172 dom = true; 173 } 174 175 Provider[] provs = Security.getProviders(); 176 for (Provider p : provs) { 177 Service s = p.getService("TransformService", algorithm); 178 if (s != null) { 179 String value = s.getAttribute("MechanismType"); 180 if ((value == null && dom) || 181 (value != null && value.equals(mechanismType))) { 182 Object obj = s.newInstance(null); 183 if (obj instanceof TransformService) { 184 TransformService ts = (TransformService) obj; 185 ts.algorithm = algorithm; 186 ts.mechanism = mechanismType; 187 ts.provider = p; 188 return ts; 189 } 190 } 191 } 192 } 193 throw new NoSuchAlgorithmException 194 (algorithm + " algorithm and " + mechanismType 195 + " mechanism not available"); 196 } 197 198 /** 199 * Returns a <code>TransformService</code> that supports the specified 200 * algorithm URI (ex: {@link Transform#XPATH2}) and mechanism type 201 * (ex: DOM) as supplied by the specified provider. Note that the specified 202 * <code>Provider</code> object does not have to be registered in the 203 * provider list. 204 * 205 * @param algorithm the URI of the algorithm. See the 206 * {@code TransformService} section in the 207 * <a href= 208 * "{@docRoot}/../specs/security/standard-names.html#xml-signature-transform-transformservice-algorithms"> 209 * Java Security Standard Algorithm Names Specification</a> for a list of 210 * standard transform algorithms. 211 * @param mechanismType the type of the XML processing mechanism and 212 * representation. See the {@code TransformService} section in the 213 * <a href= 214 * "{@docRoot}/../specs/security/standard-names.html#xml-signature-xmlsignaturefactorykeyinfofactorytransformservice-mechanisms"> 215 * Java Security Standard Algorithm Names Specification</a> for a list of 216 * standard mechanism types. 217 * @param provider the <code>Provider</code> object 218 * @return a new <code>TransformService</code> 219 * @throws NullPointerException if <code>provider</code>, 220 * <code>algorithm</code>, or <code>mechanismType</code> is 221 * <code>null</code> 222 * @throws NoSuchAlgorithmException if a <code>TransformService</code> 223 * implementation for the specified algorithm and mechanism type is not 224 * available from the specified <code>Provider</code> object 225 * @see Provider 226 */ getInstance(String algorithm, String mechanismType, Provider provider)227 public static TransformService getInstance 228 (String algorithm, String mechanismType, Provider provider) 229 throws NoSuchAlgorithmException { 230 if (mechanismType == null || algorithm == null || provider == null) { 231 throw new NullPointerException(); 232 } 233 234 boolean dom = false; 235 if (mechanismType.equals("DOM")) { 236 dom = true; 237 } 238 Service s = provider.getService("TransformService", algorithm); 239 if (s != null) { 240 String value = s.getAttribute("MechanismType"); 241 if ((value == null && dom) || 242 (value != null && value.equals(mechanismType))) { 243 Object obj = s.newInstance(null); 244 if (obj instanceof TransformService) { 245 TransformService ts = (TransformService) obj; 246 ts.algorithm = algorithm; 247 ts.mechanism = mechanismType; 248 ts.provider = provider; 249 return ts; 250 } 251 } 252 } 253 throw new NoSuchAlgorithmException 254 (algorithm + " algorithm and " + mechanismType 255 + " mechanism not available from " + provider.getName()); 256 } 257 258 /** 259 * Returns a <code>TransformService</code> that supports the specified 260 * algorithm URI (ex: {@link Transform#XPATH2}) and mechanism type 261 * (ex: DOM) as supplied by the specified provider. The specified provider 262 * must be registered in the security provider list. 263 * 264 * <p>Note that the list of registered providers may be retrieved via 265 * the {@link Security#getProviders() Security.getProviders()} method. 266 * 267 * @param algorithm the URI of the algorithm. See the 268 * {@code TransformService} section in the 269 * <a href= 270 * "{@docRoot}/../specs/security/standard-names.html#xml-signature-transform-transformservice-algorithms"> 271 * Java Security Standard Algorithm Names Specification</a> for a list of 272 * standard transform algorithms. 273 * @param mechanismType the type of the XML processing mechanism and 274 * representation. See the {@code TransformService} section in the 275 * <a href= 276 * "{@docRoot}/../specs/security/standard-names.html#xml-signature-xmlsignaturefactorykeyinfofactorytransformservice-mechanisms"> 277 * Java Security Standard Algorithm Names Specification</a> for a list of 278 * standard mechanism types. 279 * @param provider the string name of the provider 280 * @return a new <code>TransformService</code> 281 * @throws NoSuchProviderException if the specified provider is not 282 * registered in the security provider list 283 * @throws NullPointerException if <code>provider</code>, 284 * <code>mechanismType</code>, or <code>algorithm</code> is 285 * <code>null</code> 286 * @throws NoSuchAlgorithmException if a <code>TransformService</code> 287 * implementation for the specified algorithm and mechanism type is not 288 * available from the specified provider 289 * @see Provider 290 */ getInstance(String algorithm, String mechanismType, String provider)291 public static TransformService getInstance 292 (String algorithm, String mechanismType, String provider) 293 throws NoSuchAlgorithmException, NoSuchProviderException { 294 if (mechanismType == null || algorithm == null || provider == null) { 295 throw new NullPointerException(); 296 } else if (provider.length() == 0) { 297 throw new NoSuchProviderException(); 298 } 299 boolean dom = false; 300 if (mechanismType.equals("DOM")) { 301 dom = true; 302 } 303 Provider p = Security.getProvider(provider); 304 if (p == null) { 305 throw new NoSuchProviderException("No such provider: " + 306 provider); 307 } 308 Service s = p.getService("TransformService", algorithm); 309 if (s != null) { 310 String value = s.getAttribute("MechanismType"); 311 if ((value == null && dom) || 312 (value != null && value.equals(mechanismType))) { 313 Object obj = s.newInstance(null); 314 if (obj instanceof TransformService) { 315 TransformService ts = (TransformService) obj; 316 ts.algorithm = algorithm; 317 ts.mechanism = mechanismType; 318 ts.provider = p; 319 return ts; 320 } 321 } 322 } 323 throw new NoSuchAlgorithmException 324 (algorithm + " algorithm and " + mechanismType 325 + " mechanism not available from " + provider); 326 } 327 328 private static class MechanismMapEntry implements Map.Entry<String,String> { 329 private final String mechanism; 330 private final String algorithm; 331 private final String key; MechanismMapEntry(String algorithm, String mechanism)332 MechanismMapEntry(String algorithm, String mechanism) { 333 this.algorithm = algorithm; 334 this.mechanism = mechanism; 335 this.key = "TransformService." + algorithm + " MechanismType"; 336 } equals(Object o)337 public boolean equals(Object o) { 338 if (!(o instanceof Map.Entry)) { 339 return false; 340 } 341 Map.Entry<?,?> e = (Map.Entry<?,?>) o; 342 return (getKey()==null ? 343 e.getKey()==null : getKey().equals(e.getKey())) && 344 (getValue()==null ? 345 e.getValue()==null : getValue().equals(e.getValue())); 346 } getKey()347 public String getKey() { 348 return key; 349 } getValue()350 public String getValue() { 351 return mechanism; 352 } setValue(String value)353 public String setValue(String value) { 354 throw new UnsupportedOperationException(); 355 } hashCode()356 public int hashCode() { 357 return (getKey()==null ? 0 : getKey().hashCode()) ^ 358 (getValue()==null ? 0 : getValue().hashCode()); 359 } 360 } 361 362 /** 363 * Returns the mechanism type supported by this <code>TransformService</code>. 364 * 365 * @return the mechanism type 366 */ getMechanismType()367 public final String getMechanismType() { 368 return mechanism; 369 } 370 371 /** 372 * Returns the URI of the algorithm supported by this 373 * <code>TransformService</code>. 374 * 375 * @return the algorithm URI 376 */ getAlgorithm()377 public final String getAlgorithm() { 378 return algorithm; 379 } 380 381 /** 382 * Returns the provider of this <code>TransformService</code>. 383 * 384 * @return the provider 385 */ getProvider()386 public final Provider getProvider() { 387 return provider; 388 } 389 390 /** 391 * Initializes this <code>TransformService</code> with the specified 392 * parameters. 393 * 394 * <p>If the parameters exist in XML form, the 395 * {@link #init(XMLStructure, XMLCryptoContext)} method should be used to 396 * initialize the <code>TransformService</code>. 397 * 398 * @param params the algorithm parameters (may be <code>null</code> if 399 * not required or optional) 400 * @throws InvalidAlgorithmParameterException if the specified parameters 401 * are invalid for this algorithm 402 */ init(TransformParameterSpec params)403 public abstract void init(TransformParameterSpec params) 404 throws InvalidAlgorithmParameterException; 405 406 /** 407 * Marshals the algorithm-specific parameters. If there are no parameters 408 * to be marshalled, this method returns without throwing an exception. 409 * 410 * @param parent a mechanism-specific structure containing the parent 411 * node that the marshalled parameters should be appended to 412 * @param context the <code>XMLCryptoContext</code> containing 413 * additional context (may be <code>null</code> if not applicable) 414 * @throws ClassCastException if the type of <code>parent</code> or 415 * <code>context</code> is not compatible with this 416 * <code>TransformService</code> 417 * @throws NullPointerException if <code>parent</code> is <code>null</code> 418 * @throws MarshalException if the parameters cannot be marshalled 419 */ marshalParams(XMLStructure parent, XMLCryptoContext context)420 public abstract void marshalParams 421 (XMLStructure parent, XMLCryptoContext context) 422 throws MarshalException; 423 424 /** 425 * Initializes this <code>TransformService</code> with the specified 426 * parameters and document context. 427 * 428 * @param parent a mechanism-specific structure containing the parent 429 * structure 430 * @param context the <code>XMLCryptoContext</code> containing 431 * additional context (may be <code>null</code> if not applicable) 432 * @throws ClassCastException if the type of <code>parent</code> or 433 * <code>context</code> is not compatible with this 434 * <code>TransformService</code> 435 * @throws NullPointerException if <code>parent</code> is <code>null</code> 436 * @throws InvalidAlgorithmParameterException if the specified parameters 437 * are invalid for this algorithm 438 */ init(XMLStructure parent, XMLCryptoContext context)439 public abstract void init(XMLStructure parent, XMLCryptoContext context) 440 throws InvalidAlgorithmParameterException; 441 } 442