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