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 }