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 KeyResolverSpi keyResolverSpi = 186 (KeyResolverSpi) Class.forName(className).newInstance(); 187 keyResolverSpi.setGlobalResolver(globalResolver); 188 register(keyResolverSpi, false); 189 } 190 191 /** 192 * This method is used for registering {@link KeyResolverSpi}s which are 193 * available to <I>all</I> {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} objects. This means that 194 * personalized {@link KeyResolverSpi}s should only be registered directly 195 * to the {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} using 196 * {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo#registerInternalKeyResolver}. 197 * Please note that this method will create a new copy of the underlying array, as the 198 * underlying collection is a CopyOnWriteArrayList. 199 * 200 * @param className 201 * @param globalResolver Whether the KeyResolverSpi is a global resolver or not 202 * @throws SecurityException if a security manager is installed and the 203 * caller does not have permission to register the key resolver 204 */ 205 public static void registerAtStart(String className, boolean globalResolver) { 206 JavaUtils.checkRegisterPermission(); 207 KeyResolverSpi keyResolverSpi = null; 208 Exception ex = null; 209 try { 210 keyResolverSpi = (KeyResolverSpi) Class.forName(className).newInstance(); 211 } catch (ClassNotFoundException e) { 212 ex = e; 213 } catch (IllegalAccessException e) { 214 ex = e; 215 } catch (InstantiationException e) { 216 ex = e; 217 } 218 219 if (ex != null) { 220 throw (IllegalArgumentException) new 221 IllegalArgumentException("Invalid KeyResolver class name").initCause(ex); 222 } 223 keyResolverSpi.setGlobalResolver(globalResolver); 224 register(keyResolverSpi, true); 225 } 226 227 /** 228 * This method is used for registering {@link KeyResolverSpi}s which are 229 * available to <I>all</I> {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} objects. This means that 230 * personalized {@link KeyResolverSpi}s should only be registered directly 231 * to the {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} using 232 * {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo#registerInternalKeyResolver}. 233 * Please note that this method will create a new copy of the underlying array, as the 234 * underlying collection is a CopyOnWriteArrayList. 235 * 236 * @param keyResolverSpi a KeyResolverSpi instance to register 237 * @param start whether to register the KeyResolverSpi at the start of the list or not 238 * @throws SecurityException if a security manager is installed and the 239 * caller does not have permission to register the key resolver 240 */ 241 public static void register( 242 KeyResolverSpi keyResolverSpi, 243 boolean start 244 ) { 245 JavaUtils.checkRegisterPermission(); 246 KeyResolver resolver = new KeyResolver(keyResolverSpi); 247 if (start) { 248 resolverVector.add(0, resolver); 249 } else { 250 resolverVector.add(resolver); 251 } 252 } 253 254 /** 255 * This method is used for registering {@link KeyResolverSpi}s which are 256 * available to <I>all</I> {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} objects. This means that 257 * personalized {@link KeyResolverSpi}s should only be registered directly 258 * to the {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} using 259 * {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo#registerInternalKeyResolver}. 260 * The KeyResolverSpi instances are not registered as a global resolver. 261 * 262 * 263 * @param classNames 264 * @throws InstantiationException 265 * @throws IllegalAccessException 266 * @throws ClassNotFoundException 267 * @throws SecurityException if a security manager is installed and the 268 * caller does not have permission to register the key resolver 269 */ 270 public static void registerClassNames(List<String> classNames) 271 throws ClassNotFoundException, IllegalAccessException, InstantiationException { 272 JavaUtils.checkRegisterPermission(); 273 List<KeyResolver> keyResolverList = new ArrayList<KeyResolver>(classNames.size()); 274 for (String className : classNames) { 275 KeyResolverSpi keyResolverSpi = 276 (KeyResolverSpi) Class.forName(className).newInstance(); 277 keyResolverSpi.setGlobalResolver(false); 278 keyResolverList.add(new KeyResolver(keyResolverSpi)); 279 } 280 resolverVector.addAll(keyResolverList); 281 } 282 283 /** 284 * This method registers the default resolvers. 285 */ 286 public static void registerDefaultResolvers() { 287 288 List<KeyResolver> keyResolverList = new ArrayList<KeyResolver>(); 289 keyResolverList.add(new KeyResolver(new RSAKeyValueResolver())); 290 keyResolverList.add(new KeyResolver(new DSAKeyValueResolver())); 291 keyResolverList.add(new KeyResolver(new X509CertificateResolver())); 292 keyResolverList.add(new KeyResolver(new X509SKIResolver())); 293 keyResolverList.add(new KeyResolver(new RetrievalMethodResolver())); 294 keyResolverList.add(new KeyResolver(new X509SubjectNameResolver())); 295 keyResolverList.add(new KeyResolver(new X509IssuerSerialResolver())); 296 keyResolverList.add(new KeyResolver(new DEREncodedKeyValueResolver())); 297 keyResolverList.add(new KeyResolver(new KeyInfoReferenceResolver())); 298 keyResolverList.add(new KeyResolver(new X509DigestResolver())); 299 300 resolverVector.addAll(keyResolverList); 301 } 302 303 /** 304 * Method resolvePublicKey 305 * 306 * @param element 307 * @param baseURI 308 * @param storage 309 * @return resolved public key from the registered from the elements 310 * 311 * @throws KeyResolverException 312 */ 313 public PublicKey resolvePublicKey( 314 Element element, String baseURI, StorageResolver storage 315 ) throws KeyResolverException { 316 return resolverSpi.engineLookupAndResolvePublicKey(element, baseURI, storage); 317 } 318 319 /** 320 * Method resolveX509Certificate 321 * 322 * @param element 323 * @param baseURI 324 * @param storage 325 * @return resolved X509certificate key from the registered from the elements 326 * 327 * @throws KeyResolverException 328 */ 329 public X509Certificate resolveX509Certificate( 330 Element element, String baseURI, StorageResolver storage 331 ) throws KeyResolverException { 332 return resolverSpi.engineLookupResolveX509Certificate(element, baseURI, storage); 333 } 334 335 /** 336 * @param element 337 * @param baseURI 338 * @param storage 339 * @return resolved SecretKey key from the registered from the elements 340 * @throws KeyResolverException 341 */ 342 public SecretKey resolveSecretKey( 343 Element element, String baseURI, StorageResolver storage 344 ) throws KeyResolverException { 345 return resolverSpi.engineLookupAndResolveSecretKey(element, baseURI, storage); 346 } 347 348 /** 349 * Method setProperty 350 * 351 * @param key 352 * @param value 353 */ 354 public void setProperty(String key, String value) { 355 resolverSpi.engineSetProperty(key, value); 356 } 357 358 /** 359 * Method getProperty 360 * 361 * @param key 362 * @return the property set for this resolver 363 */ 364 public String getProperty(String key) { 365 return resolverSpi.engineGetProperty(key); 366 } 367 368 369 /** 370 * Method understandsProperty 371 * 372 * @param propertyToTest 373 * @return true if the resolver understands property propertyToTest 374 */ 375 public boolean understandsProperty(String propertyToTest) { 376 return resolverSpi.understandsProperty(propertyToTest); 377 } 378 379 380 /** 381 * Method resolverClassName 382 * 383 * @return the name of the resolver. 384 */ 385 public String resolverClassName() { 386 return resolverSpi.getClass().getName(); 387 } 388 389 /** 390 * Iterate over the KeyResolverSpi instances 391 */ 392 static class ResolverIterator implements Iterator<KeyResolverSpi> { 393 List<KeyResolver> res; 394 Iterator<KeyResolver> it; 395 396 public ResolverIterator(List<KeyResolver> list) { 397 res = list; 398 it = res.iterator(); 399 } 400 401 public boolean hasNext() { 402 return it.hasNext(); 403 } 404 405 public KeyResolverSpi next() { 406 KeyResolver resolver = it.next(); 407 if (resolver == null) { 408 throw new RuntimeException("utils.resolver.noClass"); 409 } 410 411 return resolver.resolverSpi; 412 } 413 414 public void remove() { 415 throw new UnsupportedOperationException("Can't remove resolvers using the iterator"); 416 } 417 }; 418 419 public static Iterator<KeyResolverSpi> iterator() { 420 return new ResolverIterator(resolverVector); 421 } 422 }