jdk/src/share/classes/sun/security/validator/PKIXValidator.java
changeset 7040 659824c2a550
parent 5782 50575882b36f
child 10709 d865c9f21240
equal deleted inserted replaced
7039:6464c8e62a18 7040:659824c2a550
    29 
    29 
    30 import java.security.*;
    30 import java.security.*;
    31 import java.security.cert.*;
    31 import java.security.cert.*;
    32 
    32 
    33 import javax.security.auth.x500.X500Principal;
    33 import javax.security.auth.x500.X500Principal;
       
    34 import sun.security.action.GetBooleanAction;
       
    35 import sun.security.provider.certpath.AlgorithmChecker;
    34 
    36 
    35 /**
    37 /**
    36  * Validator implementation built on the PKIX CertPath API. This
    38  * Validator implementation built on the PKIX CertPath API. This
    37  * implementation will be emphasized going forward.<p>
    39  * implementation will be emphasized going forward.<p>
    38  *
    40  * <p>
    39  * Note that the validate() implementation tries to use a PKIX validator
    41  * Note that the validate() implementation tries to use a PKIX validator
    40  * if that appears possible and a PKIX builder otherwise. This increases
    42  * if that appears possible and a PKIX builder otherwise. This increases
    41  * performance and currently also leads to better exception messages
    43  * performance and currently also leads to better exception messages
    42  * in case of failures.
    44  * in case of failures.
       
    45  * <p>
       
    46  * {@code PKIXValidator} objects are immutable once they have been created.
       
    47  * Please DO NOT add methods that can change the state of an instance once
       
    48  * it has been created.
    43  *
    49  *
    44  * @author Andreas Sterbenz
    50  * @author Andreas Sterbenz
    45  */
    51  */
    46 public final class PKIXValidator extends Validator {
    52 public final class PKIXValidator extends Validator {
    47 
    53 
       
    54     /**
       
    55      * Flag indicating whether to enable revocation check for the PKIX trust
       
    56      * manager. Typically, this will only work if the PKIX implementation
       
    57      * supports CRL distribution points as we do not manually setup CertStores.
       
    58      */
       
    59     private final static boolean checkTLSRevocation =
       
    60         AccessController.doPrivileged
       
    61             (new GetBooleanAction("com.sun.net.ssl.checkRevocation"));
       
    62 
    48     // enable use of the validator if possible
    63     // enable use of the validator if possible
    49     private final static boolean TRY_VALIDATOR = true;
    64     private final static boolean TRY_VALIDATOR = true;
    50 
    65 
    51     private final Set<X509Certificate> trustedCerts;
    66     private final Set<X509Certificate> trustedCerts;
    52     private final PKIXBuilderParameters parameterTemplate;
    67     private final PKIXBuilderParameters parameterTemplate;
    53     private int certPathLength = -1;
    68     private int certPathLength = -1;
    54 
    69 
    55     // needed only for the validator
    70     // needed only for the validator
    56     private Map<X500Principal, List<PublicKey>> trustedSubjects;
    71     private final Map<X500Principal, List<PublicKey>> trustedSubjects;
    57     private CertificateFactory factory;
    72     private final CertificateFactory factory;
    58 
    73 
    59     private boolean plugin = false;
    74     private final boolean plugin;
    60 
    75 
    61     PKIXValidator(String variant, Collection<X509Certificate> trustedCerts) {
    76     PKIXValidator(String variant, Collection<X509Certificate> trustedCerts) {
    62         super(TYPE_PKIX, variant);
    77         super(TYPE_PKIX, variant);
    63         if (trustedCerts instanceof Set) {
    78         if (trustedCerts instanceof Set) {
    64             this.trustedCerts = (Set<X509Certificate>)trustedCerts;
    79             this.trustedCerts = (Set<X509Certificate>)trustedCerts;
    73             parameterTemplate = new PKIXBuilderParameters(trustAnchors, null);
    88             parameterTemplate = new PKIXBuilderParameters(trustAnchors, null);
    74         } catch (InvalidAlgorithmParameterException e) {
    89         } catch (InvalidAlgorithmParameterException e) {
    75             throw new RuntimeException("Unexpected error: " + e.toString(), e);
    90             throw new RuntimeException("Unexpected error: " + e.toString(), e);
    76         }
    91         }
    77         setDefaultParameters(variant);
    92         setDefaultParameters(variant);
    78         initCommon();
    93 
       
    94         // initCommon();
       
    95         if (TRY_VALIDATOR) {
       
    96             if (TRY_VALIDATOR == false) {
       
    97                 return;
       
    98             }
       
    99             trustedSubjects = new HashMap<X500Principal, List<PublicKey>>();
       
   100             for (X509Certificate cert : trustedCerts) {
       
   101                 X500Principal dn = cert.getSubjectX500Principal();
       
   102                 List<PublicKey> keys;
       
   103                 if (trustedSubjects.containsKey(dn)) {
       
   104                     keys = trustedSubjects.get(dn);
       
   105                 } else {
       
   106                     keys = new ArrayList<PublicKey>();
       
   107                     trustedSubjects.put(dn, keys);
       
   108                 }
       
   109                 keys.add(cert.getPublicKey());
       
   110             }
       
   111             try {
       
   112                 factory = CertificateFactory.getInstance("X.509");
       
   113             } catch (CertificateException e) {
       
   114                 throw new RuntimeException("Internal error", e);
       
   115             }
       
   116             plugin = variant.equals(VAR_PLUGIN_CODE_SIGNING);
       
   117         } else {
       
   118             plugin = false;
       
   119         }
    79     }
   120     }
    80 
   121 
    81     PKIXValidator(String variant, PKIXBuilderParameters params) {
   122     PKIXValidator(String variant, PKIXBuilderParameters params) {
    82         super(TYPE_PKIX, variant);
   123         super(TYPE_PKIX, variant);
    83         trustedCerts = new HashSet<X509Certificate>();
   124         trustedCerts = new HashSet<X509Certificate>();
    86             if (cert != null) {
   127             if (cert != null) {
    87                 trustedCerts.add(cert);
   128                 trustedCerts.add(cert);
    88             }
   129             }
    89         }
   130         }
    90         parameterTemplate = params;
   131         parameterTemplate = params;
    91         initCommon();
   132 
    92     }
   133         // initCommon();
    93 
   134         if (TRY_VALIDATOR) {
    94     private void initCommon() {
   135             if (TRY_VALIDATOR == false) {
    95         if (TRY_VALIDATOR == false) {
   136                 return;
    96             return;
   137             }
    97         }
   138             trustedSubjects = new HashMap<X500Principal, List<PublicKey>>();
    98         trustedSubjects = new HashMap<X500Principal, List<PublicKey>>();
   139             for (X509Certificate cert : trustedCerts) {
    99         for (X509Certificate cert : trustedCerts) {
   140                 X500Principal dn = cert.getSubjectX500Principal();
   100             X500Principal dn = cert.getSubjectX500Principal();
   141                 List<PublicKey> keys;
   101             List<PublicKey> keys;
   142                 if (trustedSubjects.containsKey(dn)) {
   102             if (trustedSubjects.containsKey(dn)) {
   143                     keys = trustedSubjects.get(dn);
   103                 keys = trustedSubjects.get(dn);
   144                 } else {
   104             } else {
   145                     keys = new ArrayList<PublicKey>();
   105                 keys = new ArrayList<PublicKey>();
   146                     trustedSubjects.put(dn, keys);
   106                 trustedSubjects.put(dn, keys);
   147                 }
   107             }
   148                 keys.add(cert.getPublicKey());
   108             keys.add(cert.getPublicKey());
   149             }
   109         }
   150             try {
   110         try {
   151                 factory = CertificateFactory.getInstance("X.509");
   111             factory = CertificateFactory.getInstance("X.509");
   152             } catch (CertificateException e) {
   112         } catch (CertificateException e) {
   153                 throw new RuntimeException("Internal error", e);
   113             throw new RuntimeException("Internal error", e);
   154             }
   114         }
   155             plugin = variant.equals(VAR_PLUGIN_CODE_SIGNING);
   115         plugin = variant.equals(VAR_PLUGIN_CODE_SIGNING);
   156         } else {
       
   157             plugin = false;
       
   158         }
   116     }
   159     }
   117 
   160 
   118     public Collection<X509Certificate> getTrustedCertificates() {
   161     public Collection<X509Certificate> getTrustedCertificates() {
   119         return trustedCerts;
   162         return trustedCerts;
   120     }
   163     }
   127      * may modify the length of the path.
   170      * may modify the length of the path.
   128      *
   171      *
   129      * @return the length of the last certification path passed to
   172      * @return the length of the last certification path passed to
   130      *   CertPathValidator.validate, or -1 if it has not been invoked yet
   173      *   CertPathValidator.validate, or -1 if it has not been invoked yet
   131      */
   174      */
   132     public int getCertPathLength() {
   175     public int getCertPathLength() { // mutable, should be private
   133         return certPathLength;
   176         return certPathLength;
   134     }
   177     }
   135 
   178 
   136     /**
   179     /**
   137      * Set J2SE global default PKIX parameters. Currently, hardcoded to disable
   180      * Set J2SE global default PKIX parameters. Currently, hardcoded to disable
   138      * revocation checking. In the future, this should be configurable.
   181      * revocation checking. In the future, this should be configurable.
   139      */
   182      */
   140     private void setDefaultParameters(String variant) {
   183     private void setDefaultParameters(String variant) {
   141         parameterTemplate.setRevocationEnabled(false);
   184         if ((variant == Validator.VAR_TLS_SERVER) ||
       
   185                 (variant == Validator.VAR_TLS_CLIENT)) {
       
   186             parameterTemplate.setRevocationEnabled(checkTLSRevocation);
       
   187         } else {
       
   188             parameterTemplate.setRevocationEnabled(false);
       
   189         }
   142     }
   190     }
   143 
   191 
   144     /**
   192     /**
   145      * Return the PKIX parameters used by this instance. An application may
   193      * Return the PKIX parameters used by this instance. An application may
   146      * modify the parameters but must make sure not to perform any concurrent
   194      * modify the parameters but must make sure not to perform any concurrent
   147      * validations.
   195      * validations.
   148      */
   196      */
   149     public PKIXBuilderParameters getParameters() {
   197     public PKIXBuilderParameters getParameters() { // mutable, should be private
   150         return parameterTemplate;
   198         return parameterTemplate;
   151     }
   199     }
   152 
   200 
       
   201     @Override
   153     X509Certificate[] engineValidate(X509Certificate[] chain,
   202     X509Certificate[] engineValidate(X509Certificate[] chain,
   154             Collection<X509Certificate> otherCerts, Object parameter)
   203             Collection<X509Certificate> otherCerts,
   155             throws CertificateException {
   204             AlgorithmConstraints constraints,
       
   205             Object parameter) throws CertificateException {
   156         if ((chain == null) || (chain.length == 0)) {
   206         if ((chain == null) || (chain.length == 0)) {
   157             throw new CertificateException
   207             throw new CertificateException
   158                 ("null or zero-length certificate chain");
   208                 ("null or zero-length certificate chain");
   159         }
   209         }
       
   210 
       
   211         // add  new algorithm constraints checker
       
   212         PKIXBuilderParameters pkixParameters =
       
   213                     (PKIXBuilderParameters) parameterTemplate.clone();
       
   214         AlgorithmChecker algorithmChecker = null;
       
   215         if (constraints != null) {
       
   216             algorithmChecker = new AlgorithmChecker(constraints);
       
   217             pkixParameters.addCertPathChecker(algorithmChecker);
       
   218         }
       
   219 
   160         if (TRY_VALIDATOR) {
   220         if (TRY_VALIDATOR) {
   161             // check that chain is in correct order and check if chain contains
   221             // check that chain is in correct order and check if chain contains
   162             // trust anchor
   222             // trust anchor
   163             X500Principal prevIssuer = null;
   223             X500Principal prevIssuer = null;
   164             for (int i = 0; i < chain.length; i++) {
   224             for (int i = 0; i < chain.length; i++) {
   165                 X509Certificate cert = chain[i];
   225                 X509Certificate cert = chain[i];
   166                 X500Principal dn = cert.getSubjectX500Principal();
   226                 X500Principal dn = cert.getSubjectX500Principal();
   167                 if (i != 0 &&
   227                 if (i != 0 &&
   168                     !dn.equals(prevIssuer)) {
   228                     !dn.equals(prevIssuer)) {
   169                     // chain is not ordered correctly, call builder instead
   229                     // chain is not ordered correctly, call builder instead
   170                     return doBuild(chain, otherCerts);
   230                     return doBuild(chain, otherCerts, pkixParameters);
   171                 }
   231                 }
   172 
   232 
   173                 // Check if chain[i] is already trusted. It may be inside
   233                 // Check if chain[i] is already trusted. It may be inside
   174                 // trustedCerts, or has the same dn and public key as a cert
   234                 // trustedCerts, or has the same dn and public key as a cert
   175                 // inside trustedCerts. The latter happens when a CA has
   235                 // inside trustedCerts. The latter happens when a CA has
   184                         return new X509Certificate[] {chain[0]};
   244                         return new X509Certificate[] {chain[0]};
   185                     }
   245                     }
   186                     // Remove and call validator on partial chain [0 .. i-1]
   246                     // Remove and call validator on partial chain [0 .. i-1]
   187                     X509Certificate[] newChain = new X509Certificate[i];
   247                     X509Certificate[] newChain = new X509Certificate[i];
   188                     System.arraycopy(chain, 0, newChain, 0, i);
   248                     System.arraycopy(chain, 0, newChain, 0, i);
   189                     return doValidate(newChain);
   249                     return doValidate(newChain, pkixParameters);
   190                 }
   250                 }
   191                 prevIssuer = cert.getIssuerX500Principal();
   251                 prevIssuer = cert.getIssuerX500Principal();
   192             }
   252             }
   193 
   253 
   194             // apparently issued by trust anchor?
   254             // apparently issued by trust anchor?
   195             X509Certificate last = chain[chain.length - 1];
   255             X509Certificate last = chain[chain.length - 1];
   196             X500Principal issuer = last.getIssuerX500Principal();
   256             X500Principal issuer = last.getIssuerX500Principal();
   197             X500Principal subject = last.getSubjectX500Principal();
   257             X500Principal subject = last.getSubjectX500Principal();
   198             if (trustedSubjects.containsKey(issuer) &&
   258             if (trustedSubjects.containsKey(issuer) &&
   199                     isSignatureValid(trustedSubjects.get(issuer), last)) {
   259                     isSignatureValid(trustedSubjects.get(issuer), last)) {
   200                 return doValidate(chain);
   260                 return doValidate(chain, pkixParameters);
   201             }
   261             }
   202 
   262 
   203             // don't fallback to builder if called from plugin/webstart
   263             // don't fallback to builder if called from plugin/webstart
   204             if (plugin) {
   264             if (plugin) {
   205                 // Validate chain even if no trust anchor is found. This
   265                 // Validate chain even if no trust anchor is found. This
   207                 // otherwise valid
   267                 // otherwise valid
   208                 if (chain.length > 1) {
   268                 if (chain.length > 1) {
   209                     X509Certificate[] newChain =
   269                     X509Certificate[] newChain =
   210                         new X509Certificate[chain.length-1];
   270                         new X509Certificate[chain.length-1];
   211                     System.arraycopy(chain, 0, newChain, 0, newChain.length);
   271                     System.arraycopy(chain, 0, newChain, 0, newChain.length);
       
   272 
   212                     // temporarily set last cert as sole trust anchor
   273                     // temporarily set last cert as sole trust anchor
   213                     PKIXBuilderParameters params =
       
   214                         (PKIXBuilderParameters) parameterTemplate.clone();
       
   215                     try {
   274                     try {
   216                         params.setTrustAnchors
   275                         pkixParameters.setTrustAnchors
   217                             (Collections.singleton(new TrustAnchor
   276                             (Collections.singleton(new TrustAnchor
   218                                 (chain[chain.length-1], null)));
   277                                 (chain[chain.length-1], null)));
   219                     } catch (InvalidAlgorithmParameterException iape) {
   278                     } catch (InvalidAlgorithmParameterException iape) {
   220                         // should never occur, but ...
   279                         // should never occur, but ...
   221                         throw new CertificateException(iape);
   280                         throw new CertificateException(iape);
   222                     }
   281                     }
   223                     doValidate(newChain, params);
   282                     doValidate(newChain, pkixParameters);
   224                 }
   283                 }
   225                 // if the rest of the chain is valid, throw exception
   284                 // if the rest of the chain is valid, throw exception
   226                 // indicating no trust anchor was found
   285                 // indicating no trust anchor was found
   227                 throw new ValidatorException
   286                 throw new ValidatorException
   228                     (ValidatorException.T_NO_TRUST_ANCHOR);
   287                     (ValidatorException.T_NO_TRUST_ANCHOR);
   229             }
   288             }
   230             // otherwise, fall back to builder
   289             // otherwise, fall back to builder
   231         }
   290         }
   232 
   291 
   233         return doBuild(chain, otherCerts);
   292         return doBuild(chain, otherCerts, pkixParameters);
   234     }
   293     }
   235 
   294 
   236     private boolean isSignatureValid(List<PublicKey> keys, X509Certificate sub) {
   295     private boolean isSignatureValid(List<PublicKey> keys,
       
   296             X509Certificate sub) {
   237         if (plugin) {
   297         if (plugin) {
   238             for (PublicKey key: keys) {
   298             for (PublicKey key: keys) {
   239                 try {
   299                 try {
   240                     sub.verify(key);
   300                     sub.verify(key);
   241                     return true;
   301                     return true;
   271         if (date != null) {
   331         if (date != null) {
   272             params.setDate(date);
   332             params.setDate(date);
   273         }
   333         }
   274     }
   334     }
   275 
   335 
   276     private X509Certificate[] doValidate(X509Certificate[] chain)
       
   277             throws CertificateException {
       
   278         PKIXBuilderParameters params =
       
   279             (PKIXBuilderParameters)parameterTemplate.clone();
       
   280         return doValidate(chain, params);
       
   281     }
       
   282 
       
   283     private X509Certificate[] doValidate(X509Certificate[] chain,
   336     private X509Certificate[] doValidate(X509Certificate[] chain,
   284             PKIXBuilderParameters params) throws CertificateException {
   337             PKIXBuilderParameters params) throws CertificateException {
   285         try {
   338         try {
   286             setDate(params);
   339             setDate(params);
   287 
   340 
   298                 ("PKIX path validation failed: " + e.toString(), e);
   351                 ("PKIX path validation failed: " + e.toString(), e);
   299         }
   352         }
   300     }
   353     }
   301 
   354 
   302     private X509Certificate[] doBuild(X509Certificate[] chain,
   355     private X509Certificate[] doBuild(X509Certificate[] chain,
   303         Collection<X509Certificate> otherCerts) throws CertificateException {
   356         Collection<X509Certificate> otherCerts,
       
   357         PKIXBuilderParameters params) throws CertificateException {
   304 
   358 
   305         try {
   359         try {
   306             PKIXBuilderParameters params =
       
   307                 (PKIXBuilderParameters)parameterTemplate.clone();
       
   308             setDate(params);
   360             setDate(params);
   309 
   361 
   310             // setup target constraints
   362             // setup target constraints
   311             X509CertSelector selector = new X509CertSelector();
   363             X509CertSelector selector = new X509CertSelector();
   312             selector.setCertificate(chain[0]);
   364             selector.setCertificate(chain[0]);