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.keys.keyresolver; 24 25 import java.security.PublicKey; 26 import java.security.cert.X509Certificate; 27 import java.util.ArrayList; 28 import java.util.Iterator; 29 import java.util.List; 30 import java.util.concurrent.CopyOnWriteArrayList; 31 32 import javax.crypto.SecretKey; 33 34 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.DEREncodedKeyValueResolver; 35 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.DSAKeyValueResolver; 36 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.KeyInfoReferenceResolver; 37 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.RSAKeyValueResolver; 38 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.RetrievalMethodResolver; 39 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.X509CertificateResolver; 40 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.X509DigestResolver; 41 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.X509IssuerSerialResolver; 42 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.X509SKIResolver; 43 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.X509SubjectNameResolver; 44 import com.sun.org.apache.xml.internal.security.keys.storage.StorageResolver; 45 import com.sun.org.apache.xml.internal.security.utils.JavaUtils; 46 import org.w3c.dom.Element; 47 import org.w3c.dom.Node; 48 49 /** 50 * KeyResolver is factory class for subclass of KeyResolverSpi that 51 * represent child element of KeyInfo. 52 */ 53 public class KeyResolver { 54 55 /** {@link org.apache.commons.logging} logging facility */ 56 private static java.util.logging.Logger log = 57 java.util.logging.Logger.getLogger(KeyResolver.class.getName()); 58 59 /** Field resolverVector */ 60 private static List<KeyResolver> resolverVector = new CopyOnWriteArrayList<KeyResolver>(); 61 62 /** Field resolverSpi */ 63 private final KeyResolverSpi resolverSpi; 64 65 /** 66 * Constructor. 67 * 68 * @param keyResolverSpi a KeyResolverSpi instance 69 */ 70 private KeyResolver(KeyResolverSpi keyResolverSpi) { 71 resolverSpi = keyResolverSpi; 72 } 73 74 /** 75 * Method length 76 * 77 * @return the length of resolvers registered 78 */ 79 public static int length() { 80 return resolverVector.size(); 81 } 82 83 /** 84 * Method getX509Certificate 85 * 86 * @param element 87 * @param baseURI 88 * @param storage 89 * @return The certificate represented by the element. 90 * 91 * @throws KeyResolverException 92 */ 93 public static final X509Certificate getX509Certificate( 94 Element element, String baseURI, StorageResolver storage 95 ) throws KeyResolverException { 96 for (KeyResolver resolver : resolverVector) { 97 if (resolver == null) { 98 Object exArgs[] = { 99 (((element != null) 100 && (element.getNodeType() == Node.ELEMENT_NODE)) 101 ? element.getTagName() : "null") 102 }; 103 104 throw new KeyResolverException("utils.resolver.noClass", exArgs); 105 } 106 if (log.isLoggable(java.util.logging.Level.FINE)) { 107 log.log(java.util.logging.Level.FINE, "check resolvability by class " + resolver.getClass()); 108 } 109 110 X509Certificate cert = resolver.resolveX509Certificate(element, baseURI, storage); 111 if (cert != null) { 112 return cert; 113 } 114 } 115 116 Object exArgs[] = { 117 (((element != null) && (element.getNodeType() == Node.ELEMENT_NODE)) 118 ? element.getTagName() : "null") 119 }; 120 121 throw new KeyResolverException("utils.resolver.noClass", exArgs); 122 } 123 124 /** 125 * Method getPublicKey 126 * 127 * @param element 128 * @param baseURI 129 * @param storage 130 * @return the public key contained in the element 131 * 132 * @throws KeyResolverException 133 */ 134 public static final PublicKey getPublicKey( 135 Element element, String baseURI, StorageResolver storage 136 ) throws KeyResolverException { 137 for (KeyResolver resolver : resolverVector) { 138 if (resolver == null) { 139 Object exArgs[] = { 140 (((element != null) 141 && (element.getNodeType() == Node.ELEMENT_NODE)) 142 ? element.getTagName() : "null") 143 }; 144 145 throw new KeyResolverException("utils.resolver.noClass", exArgs); 146 } 147 if (log.isLoggable(java.util.logging.Level.FINE)) { 148 log.log(java.util.logging.Level.FINE, "check resolvability by class " + resolver.getClass()); 149 } 150 151 PublicKey cert = resolver.resolvePublicKey(element, baseURI, storage); 152 if (cert != null) { 153 return cert; 154 } 155 } 156 157 Object exArgs[] = { 158 (((element != null) && (element.getNodeType() == Node.ELEMENT_NODE)) 159 ? element.getTagName() : "null") 160 }; 161 162 throw new KeyResolverException("utils.resolver.noClass", exArgs); 163 } 164 165 /** 166 * This method is used for registering {@link KeyResolverSpi}s which are 167 * available to <I>all</I> {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} objects. This means that 168 * personalized {@link KeyResolverSpi}s should only be registered directly 169 * to the {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} using 170 * {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo#registerInternalKeyResolver}. 171 * Please note that this method will create a new copy of the underlying array, as the 172 * underlying collection is a CopyOnWriteArrayList. 173 * 174 * @param className 175 * @param globalResolver Whether the KeyResolverSpi is a global resolver or not 176 * @throws InstantiationException 177 * @throws IllegalAccessException 178 * @throws ClassNotFoundException 179 * @throws SecurityException if a security manager is installed and the 180 * caller does not have permission to register the key resolver 181 */ 182 public static void register(String className, boolean globalResolver) 183 throws ClassNotFoundException, IllegalAccessException, InstantiationException { 184 JavaUtils.checkRegisterPermission(); 185 @SuppressWarnings("deprecation") 186 KeyResolverSpi keyResolverSpi = 187 (KeyResolverSpi) Class.forName(className).newInstance(); 188 keyResolverSpi.setGlobalResolver(globalResolver); 189 register(keyResolverSpi, false); 190 } 191 192 /** 193 * This method is used for registering {@link KeyResolverSpi}s which are 194 * available to <I>all</I> {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} objects. This means that 195 * personalized {@link KeyResolverSpi}s should only be registered directly 196 * to the {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} using 197 * {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo#registerInternalKeyResolver}. 198 * Please note that this method will create a new copy of the underlying array, as the 199 * underlying collection is a CopyOnWriteArrayList. 200 * 201 * @param className 202 * @param globalResolver Whether the KeyResolverSpi is a global resolver or not 203 * @throws SecurityException if a security manager is installed and the 204 * caller does not have permission to register the key resolver 205 */ 206 public static void registerAtStart(String className, boolean globalResolver) { 207 JavaUtils.checkRegisterPermission(); 208 KeyResolverSpi keyResolverSpi = null; 209 Exception ex = null; 210 try { 211 @SuppressWarnings("deprecation") 212 Object tmp = Class.forName(className).newInstance(); 213 keyResolverSpi = (KeyResolverSpi) tmp; 214 } catch (ClassNotFoundException e) { 215 ex = e; 216 } catch (IllegalAccessException e) { 217 ex = e; 218 } catch (InstantiationException e) { 219 ex = e; 220 } 221 222 if (ex != null) { 223 throw (IllegalArgumentException) new 224 IllegalArgumentException("Invalid KeyResolver class name").initCause(ex); 225 } 226 keyResolverSpi.setGlobalResolver(globalResolver); 227 register(keyResolverSpi, true); 228 } 229 230 /** 231 * This method is used for registering {@link KeyResolverSpi}s which are 232 * available to <I>all</I> {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} objects. This means that 233 * personalized {@link KeyResolverSpi}s should only be registered directly 234 * to the {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} using 235 * {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo#registerInternalKeyResolver}. 236 * Please note that this method will create a new copy of the underlying array, as the 237 * underlying collection is a CopyOnWriteArrayList. 238 * 239 * @param keyResolverSpi a KeyResolverSpi instance to register 240 * @param start whether to register the KeyResolverSpi at the start of the list or not 241 * @throws SecurityException if a security manager is installed and the 242 * caller does not have permission to register the key resolver 243 */ 244 public static void register( 245 KeyResolverSpi keyResolverSpi, 246 boolean start 247 ) { 248 JavaUtils.checkRegisterPermission(); 249 KeyResolver resolver = new KeyResolver(keyResolverSpi); 250 if (start) { 251 resolverVector.add(0, resolver); 252 } else { 253 resolverVector.add(resolver); 254 } 255 } 256 257 /** 258 * This method is used for registering {@link KeyResolverSpi}s which are 259 * available to <I>all</I> {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} objects. This means that 260 * personalized {@link KeyResolverSpi}s should only be registered directly 261 * to the {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} using 262 * {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo#registerInternalKeyResolver}. 263 * The KeyResolverSpi instances are not registered as a global resolver. 264 * 265 * 266 * @param classNames 267 * @throws InstantiationException 268 * @throws IllegalAccessException 269 * @throws ClassNotFoundException 270 * @throws SecurityException if a security manager is installed and the 271 * caller does not have permission to register the key resolver 272 */ 273 public static void registerClassNames(List<String> classNames) 274 throws ClassNotFoundException, IllegalAccessException, InstantiationException { 275 JavaUtils.checkRegisterPermission(); 276 List<KeyResolver> keyResolverList = new ArrayList<KeyResolver>(classNames.size()); 277 for (String className : classNames) { 278 @SuppressWarnings("deprecation") 279 KeyResolverSpi keyResolverSpi = 280 (KeyResolverSpi) Class.forName(className).newInstance(); 281 keyResolverSpi.setGlobalResolver(false); 282 keyResolverList.add(new KeyResolver(keyResolverSpi)); 283 } 284 resolverVector.addAll(keyResolverList); 285 } 286 287 /** 288 * This method registers the default resolvers. 289 */ 290 public static void registerDefaultResolvers() { 291 292 List<KeyResolver> keyResolverList = new ArrayList<KeyResolver>(); 293 keyResolverList.add(new KeyResolver(new RSAKeyValueResolver())); 294 keyResolverList.add(new KeyResolver(new DSAKeyValueResolver())); 295 keyResolverList.add(new KeyResolver(new X509CertificateResolver())); 296 keyResolverList.add(new KeyResolver(new X509SKIResolver())); 297 keyResolverList.add(new KeyResolver(new RetrievalMethodResolver())); 298 keyResolverList.add(new KeyResolver(new X509SubjectNameResolver())); 299 keyResolverList.add(new KeyResolver(new X509IssuerSerialResolver())); 300 keyResolverList.add(new KeyResolver(new DEREncodedKeyValueResolver())); 301 keyResolverList.add(new KeyResolver(new KeyInfoReferenceResolver())); 302 keyResolverList.add(new KeyResolver(new X509DigestResolver())); 303 304 resolverVector.addAll(keyResolverList); 305 } 306 307 /** 308 * Method resolvePublicKey 309 * 310 * @param element 311 * @param baseURI 312 * @param storage 313 * @return resolved public key from the registered from the elements 314 * 315 * @throws KeyResolverException 316 */ 317 public PublicKey resolvePublicKey( 318 Element element, String baseURI, StorageResolver storage 319 ) throws KeyResolverException { 320 return resolverSpi.engineLookupAndResolvePublicKey(element, baseURI, storage); 321 } 322 323 /** 324 * Method resolveX509Certificate 325 * 326 * @param element 327 * @param baseURI 328 * @param storage 329 * @return resolved X509certificate key from the registered from the elements 330 * 331 * @throws KeyResolverException 332 */ 333 public X509Certificate resolveX509Certificate( 334 Element element, String baseURI, StorageResolver storage 335 ) throws KeyResolverException { 336 return resolverSpi.engineLookupResolveX509Certificate(element, baseURI, storage); 337 } 338 339 /** 340 * @param element 341 * @param baseURI 342 * @param storage 343 * @return resolved SecretKey key from the registered from the elements 344 * @throws KeyResolverException 345 */ 346 public SecretKey resolveSecretKey( 347 Element element, String baseURI, StorageResolver storage 348 ) throws KeyResolverException { 349 return resolverSpi.engineLookupAndResolveSecretKey(element, baseURI, storage); 350 } 351 352 /** 353 * Method setProperty 354 * 355 * @param key 356 * @param value 357 */ 358 public void setProperty(String key, String value) { 359 resolverSpi.engineSetProperty(key, value); 360 } 361 362 /** 363 * Method getProperty 364 * 365 * @param key 366 * @return the property set for this resolver 367 */ 368 public String getProperty(String key) { 369 return resolverSpi.engineGetProperty(key); 370 } 371 372 373 /** 374 * Method understandsProperty 375 * 376 * @param propertyToTest 377 * @return true if the resolver understands property propertyToTest 378 */ 379 public boolean understandsProperty(String propertyToTest) { 380 return resolverSpi.understandsProperty(propertyToTest); 381 } 382 383 384 /** 385 * Method resolverClassName 386 * 387 * @return the name of the resolver. 388 */ 389 public String resolverClassName() { 390 return resolverSpi.getClass().getName(); 391 } 392 393 /** 394 * Iterate over the KeyResolverSpi instances 395 */ 396 static class ResolverIterator implements Iterator<KeyResolverSpi> { 397 List<KeyResolver> res; 398 Iterator<KeyResolver> it; 399 400 public ResolverIterator(List<KeyResolver> list) { 401 res = list; 402 it = res.iterator(); 403 } 404 405 public boolean hasNext() { 406 return it.hasNext(); 407 } 408 409 public KeyResolverSpi next() { 410 KeyResolver resolver = it.next(); 411 if (resolver == null) { 412 throw new RuntimeException("utils.resolver.noClass"); 413 } 414 415 return resolver.resolverSpi; 416 } 417 418 public void remove() { 419 throw new UnsupportedOperationException("Can't remove resolvers using the iterator"); 420 } 421 }; 422 423 public static Iterator<KeyResolverSpi> iterator() { 424 return new ResolverIterator(resolverVector); 425 } 426 }