Home | History | Annotate | Download | only in certpath
      1 /*
      2  * Copyright (c) 2012, 2015, 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 package sun.security.provider.certpath;
     26 
     27 import java.security.InvalidAlgorithmParameterException;
     28 import java.security.PublicKey;
     29 import java.security.cert.*;
     30 import java.security.interfaces.DSAPublicKey;
     31 import java.util.*;
     32 import javax.security.auth.x500.X500Principal;
     33 
     34 import sun.security.util.Debug;
     35 
     36 /**
     37  * Common utility methods and classes used by the PKIX CertPathValidator and
     38  * CertPathBuilder implementation.
     39  */
     40 class PKIX {
     41 
     42     private static final Debug debug = Debug.getInstance("certpath");
     43 
     44     private PKIX() { }
     45 
     46     static boolean isDSAPublicKeyWithoutParams(PublicKey publicKey) {
     47         return (publicKey instanceof DSAPublicKey &&
     48                ((DSAPublicKey)publicKey).getParams() == null);
     49     }
     50 
     51     static ValidatorParams checkParams(CertPath cp, CertPathParameters params)
     52         throws InvalidAlgorithmParameterException
     53     {
     54         if (!(params instanceof PKIXParameters)) {
     55             throw new InvalidAlgorithmParameterException("inappropriate "
     56                 + "params, must be an instance of PKIXParameters");
     57         }
     58         return new ValidatorParams(cp, (PKIXParameters)params);
     59     }
     60 
     61     static BuilderParams checkBuilderParams(CertPathParameters params)
     62         throws InvalidAlgorithmParameterException
     63     {
     64         if (!(params instanceof PKIXBuilderParameters)) {
     65             throw new InvalidAlgorithmParameterException("inappropriate "
     66                 + "params, must be an instance of PKIXBuilderParameters");
     67         }
     68         return new BuilderParams((PKIXBuilderParameters)params);
     69     }
     70 
     71     /**
     72      * PKIXParameters that are shared by the PKIX CertPathValidator
     73      * implementation. Provides additional functionality and avoids
     74      * unnecessary cloning.
     75      */
     76     static class ValidatorParams {
     77         private final PKIXParameters params;
     78         private CertPath certPath;
     79         private List<PKIXCertPathChecker> checkers;
     80         private List<CertStore> stores;
     81         private boolean gotDate;
     82         private Date date;
     83         private Set<String> policies;
     84         private boolean gotConstraints;
     85         private CertSelector constraints;
     86         private Set<TrustAnchor> anchors;
     87         private List<X509Certificate> certs;
     88 
     89         ValidatorParams(CertPath cp, PKIXParameters params)
     90             throws InvalidAlgorithmParameterException
     91         {
     92             this(params);
     93             if (!cp.getType().equals("X.509") && !cp.getType().equals("X509")) {
     94                 throw new InvalidAlgorithmParameterException("inappropriate "
     95                     + "CertPath type specified, must be X.509 or X509");
     96             }
     97             this.certPath = cp;
     98         }
     99 
    100         ValidatorParams(PKIXParameters params)
    101             throws InvalidAlgorithmParameterException
    102         {
    103             this.anchors = params.getTrustAnchors();
    104             // Make sure that none of the trust anchors include name constraints
    105             // (not supported).
    106             for (TrustAnchor anchor : this.anchors) {
    107                 if (anchor.getNameConstraints() != null) {
    108                     throw new InvalidAlgorithmParameterException
    109                         ("name constraints in trust anchor not supported");
    110                 }
    111             }
    112             this.params = params;
    113         }
    114 
    115         CertPath certPath() {
    116             return certPath;
    117         }
    118         // called by CertPathBuilder after path has been built
    119         void setCertPath(CertPath cp) {
    120             this.certPath = cp;
    121         }
    122         List<X509Certificate> certificates() {
    123             if (certs == null) {
    124                 if (certPath == null) {
    125                     certs = Collections.emptyList();
    126                 } else {
    127                     // Reverse the ordering for validation so that the target
    128                     // cert is the last certificate
    129                     @SuppressWarnings("unchecked")
    130                     List<X509Certificate> xc = new ArrayList<>
    131                         ((List<X509Certificate>)certPath.getCertificates());
    132                     Collections.reverse(xc);
    133                     certs = xc;
    134                 }
    135             }
    136             return certs;
    137         }
    138         List<PKIXCertPathChecker> certPathCheckers() {
    139             if (checkers == null)
    140                 checkers = params.getCertPathCheckers();
    141             return checkers;
    142         }
    143         List<CertStore> certStores() {
    144             if (stores == null)
    145                 stores = params.getCertStores();
    146             return stores;
    147         }
    148         Date date() {
    149             if (!gotDate) {
    150                 date = params.getDate();
    151                 if (date == null)
    152                     date = new Date();
    153                 gotDate = true;
    154             }
    155             return date;
    156         }
    157         Set<String> initialPolicies() {
    158             if (policies == null)
    159                 policies = params.getInitialPolicies();
    160             return policies;
    161         }
    162         CertSelector targetCertConstraints() {
    163             if (!gotConstraints) {
    164                 constraints = params.getTargetCertConstraints();
    165                 gotConstraints = true;
    166             }
    167             return constraints;
    168         }
    169         Set<TrustAnchor> trustAnchors() {
    170             return anchors;
    171         }
    172         boolean revocationEnabled() {
    173             return params.isRevocationEnabled();
    174         }
    175         boolean policyMappingInhibited() {
    176             return params.isPolicyMappingInhibited();
    177         }
    178         boolean explicitPolicyRequired() {
    179             return params.isExplicitPolicyRequired();
    180         }
    181         boolean policyQualifiersRejected() {
    182             return params.getPolicyQualifiersRejected();
    183         }
    184         String sigProvider() { return params.getSigProvider(); }
    185         boolean anyPolicyInhibited() { return params.isAnyPolicyInhibited(); }
    186 
    187         // in rare cases we need access to the original params, for example
    188         // in order to clone CertPathCheckers before building a new chain
    189         PKIXParameters getPKIXParameters() {
    190             return params;
    191         }
    192     }
    193 
    194     static class BuilderParams extends ValidatorParams {
    195         private PKIXBuilderParameters params;
    196         private List<CertStore> stores;
    197         private X500Principal targetSubject;
    198 
    199         BuilderParams(PKIXBuilderParameters params)
    200             throws InvalidAlgorithmParameterException
    201         {
    202             super(params);
    203             checkParams(params);
    204         }
    205         private void checkParams(PKIXBuilderParameters params)
    206             throws InvalidAlgorithmParameterException
    207         {
    208             CertSelector sel = targetCertConstraints();
    209             if (!(sel instanceof X509CertSelector)) {
    210                 throw new InvalidAlgorithmParameterException("the "
    211                     + "targetCertConstraints parameter must be an "
    212                     + "X509CertSelector");
    213             }
    214             this.params = params;
    215             this.targetSubject = getTargetSubject(
    216                 certStores(), (X509CertSelector)targetCertConstraints());
    217         }
    218         @Override List<CertStore> certStores() {
    219             if (stores == null) {
    220                 // reorder CertStores so that local CertStores are tried first
    221                 stores = new ArrayList<>(params.getCertStores());
    222                 Collections.sort(stores, new CertStoreComparator());
    223             }
    224             return stores;
    225         }
    226         int maxPathLength() { return params.getMaxPathLength(); }
    227         PKIXBuilderParameters params() { return params; }
    228         X500Principal targetSubject() { return targetSubject; }
    229 
    230         /**
    231          * Returns the target subject DN from the first X509Certificate that
    232          * is fetched that matches the specified X509CertSelector.
    233          */
    234         private static X500Principal getTargetSubject(List<CertStore> stores,
    235                                                       X509CertSelector sel)
    236             throws InvalidAlgorithmParameterException
    237         {
    238             X500Principal subject = sel.getSubject();
    239             if (subject != null) {
    240                 return subject;
    241             }
    242             X509Certificate cert = sel.getCertificate();
    243             if (cert != null) {
    244                 subject = cert.getSubjectX500Principal();
    245             }
    246             if (subject != null) {
    247                 return subject;
    248             }
    249             for (CertStore store : stores) {
    250                 try {
    251                     Collection<? extends Certificate> certs =
    252                         (Collection<? extends Certificate>)
    253                             store.getCertificates(sel);
    254                     if (!certs.isEmpty()) {
    255                         X509Certificate xc =
    256                             (X509Certificate)certs.iterator().next();
    257                         return xc.getSubjectX500Principal();
    258                     }
    259                 } catch (CertStoreException e) {
    260                     // ignore but log it
    261                     if (debug != null) {
    262                         debug.println("BuilderParams.getTargetSubjectDN: " +
    263                             "non-fatal exception retrieving certs: " + e);
    264                         e.printStackTrace();
    265                     }
    266                 }
    267             }
    268             throw new InvalidAlgorithmParameterException
    269                 ("Could not determine unique target subject");
    270         }
    271     }
    272 
    273     /**
    274      * A CertStoreException with additional information about the type of
    275      * CertStore that generated the exception.
    276      */
    277     static class CertStoreTypeException extends CertStoreException {
    278         private static final long serialVersionUID = 7463352639238322556L;
    279 
    280         private final String type;
    281 
    282         CertStoreTypeException(String type, CertStoreException cse) {
    283             super(cse.getMessage(), cse.getCause());
    284             this.type = type;
    285         }
    286         String getType() {
    287             return type;
    288         }
    289     }
    290 
    291     /**
    292      * Comparator that orders CertStores so that local CertStores come before
    293      * remote CertStores.
    294      */
    295     private static class CertStoreComparator implements Comparator<CertStore> {
    296         @Override
    297         public int compare(CertStore store1, CertStore store2) {
    298             if (store1.getType().equals("Collection") ||
    299                 store1.getCertStoreParameters() instanceof
    300                 CollectionCertStoreParameters) {
    301                 return -1;
    302             } else {
    303                 return 1;
    304             }
    305         }
    306     }
    307 }
    308