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 }