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 
PKIX()44     private PKIX() { }
45 
isDSAPublicKeyWithoutParams(PublicKey publicKey)46     static boolean isDSAPublicKeyWithoutParams(PublicKey publicKey) {
47         return (publicKey instanceof DSAPublicKey &&
48                ((DSAPublicKey)publicKey).getParams() == null);
49     }
50 
checkParams(CertPath cp, CertPathParameters params)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 
checkBuilderParams(CertPathParameters params)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 
ValidatorParams(CertPath cp, PKIXParameters params)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 
ValidatorParams(PKIXParameters params)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 
certPath()115         CertPath certPath() {
116             return certPath;
117         }
118         // called by CertPathBuilder after path has been built
setCertPath(CertPath cp)119         void setCertPath(CertPath cp) {
120             this.certPath = cp;
121         }
certificates()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         }
certPathCheckers()138         List<PKIXCertPathChecker> certPathCheckers() {
139             if (checkers == null)
140                 checkers = params.getCertPathCheckers();
141             return checkers;
142         }
certStores()143         List<CertStore> certStores() {
144             if (stores == null)
145                 stores = params.getCertStores();
146             return stores;
147         }
date()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         }
initialPolicies()157         Set<String> initialPolicies() {
158             if (policies == null)
159                 policies = params.getInitialPolicies();
160             return policies;
161         }
targetCertConstraints()162         CertSelector targetCertConstraints() {
163             if (!gotConstraints) {
164                 constraints = params.getTargetCertConstraints();
165                 gotConstraints = true;
166             }
167             return constraints;
168         }
trustAnchors()169         Set<TrustAnchor> trustAnchors() {
170             return anchors;
171         }
revocationEnabled()172         boolean revocationEnabled() {
173             return params.isRevocationEnabled();
174         }
policyMappingInhibited()175         boolean policyMappingInhibited() {
176             return params.isPolicyMappingInhibited();
177         }
explicitPolicyRequired()178         boolean explicitPolicyRequired() {
179             return params.isExplicitPolicyRequired();
180         }
policyQualifiersRejected()181         boolean policyQualifiersRejected() {
182             return params.getPolicyQualifiersRejected();
183         }
sigProvider()184         String sigProvider() { return params.getSigProvider(); }
anyPolicyInhibited()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
getPKIXParameters()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 
BuilderParams(PKIXBuilderParameters params)199         BuilderParams(PKIXBuilderParameters params)
200             throws InvalidAlgorithmParameterException
201         {
202             super(params);
203             checkParams(params);
204         }
checkParams(PKIXBuilderParameters params)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         }
certStores()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         }
maxPathLength()226         int maxPathLength() { return params.getMaxPathLength(); }
params()227         PKIXBuilderParameters params() { return params; }
targetSubject()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          */
getTargetSubject(List<CertStore> stores, X509CertSelector sel)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 
CertStoreTypeException(String type, CertStoreException cse)282         CertStoreTypeException(String type, CertStoreException cse) {
283             super(cse.getMessage(), cse.getCause());
284             this.type = type;
285         }
getType()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
compare(CertStore store1, CertStore store2)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