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