1 /* 2 * Copyright (c) 2000, 2013, 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 26 package sun.security.provider.certpath; 27 28 import java.io.IOException; 29 import java.security.PublicKey; 30 import java.security.cert.CertificateException; 31 import java.security.cert.CertPathValidatorException; 32 import java.security.cert.PKIXCertPathChecker; 33 import java.security.cert.PKIXRevocationChecker; 34 import java.security.cert.TrustAnchor; 35 import java.security.cert.X509Certificate; 36 import java.util.ArrayList; 37 import java.util.HashSet; 38 import java.util.List; 39 import java.util.ListIterator; 40 import java.util.Set; 41 import javax.security.auth.x500.X500Principal; 42 43 import sun.security.provider.certpath.PKIX.BuilderParams; 44 import sun.security.util.Debug; 45 import sun.security.x509.NameConstraintsExtension; 46 import sun.security.x509.SubjectKeyIdentifierExtension; 47 import sun.security.x509.X509CertImpl; 48 49 /** 50 * A specification of a reverse PKIX validation state 51 * which is initialized by each build and updated each time a 52 * certificate is added to the current path. 53 * @since 1.4 54 * @author Sean Mullan 55 * @author Yassir Elley 56 */ 57 58 class ReverseState implements State { 59 60 private static final Debug debug = Debug.getInstance("certpath"); 61 62 /* The subject DN of the last cert in the path */ 63 X500Principal subjectDN; 64 65 /* The subject public key of the last cert */ 66 PublicKey pubKey; 67 68 /* The subject key identifier extension (if any) of the last cert */ 69 SubjectKeyIdentifierExtension subjKeyId; 70 71 /* The PKIX constrained/excluded subtrees state variable */ 72 NameConstraintsExtension nc; 73 74 /* The PKIX explicit policy, policy mapping, and inhibit_any-policy 75 state variables */ 76 int explicitPolicy; 77 int policyMapping; 78 int inhibitAnyPolicy; 79 int certIndex; 80 PolicyNodeImpl rootNode; 81 82 /* The number of remaining CA certs which may follow in the path. 83 * -1: previous cert was an EE cert 84 * 0: only EE certs may follow. 85 * >0 and <Integer.MAX_VALUE:no more than this number of CA certs may follow 86 * Integer.MAX_VALUE: unlimited 87 */ 88 int remainingCACerts; 89 90 /* The list of user-defined checkers retrieved from the PKIXParameters 91 * instance */ 92 ArrayList<PKIXCertPathChecker> userCheckers; 93 94 /* Flag indicating if state is initial (path is just starting) */ 95 private boolean init = true; 96 97 /* the checker used for revocation status */ 98 RevocationChecker revChecker; 99 100 /* the algorithm checker */ 101 AlgorithmChecker algorithmChecker; 102 103 /* the untrusted certificates checker */ 104 UntrustedChecker untrustedChecker; 105 106 /* the trust anchor used to validate the path */ 107 TrustAnchor trustAnchor; 108 109 /* Flag indicating if current cert can vouch for the CRL for 110 * the next cert 111 */ 112 boolean crlSign = true; 113 114 /** 115 * Returns a boolean flag indicating if the state is initial 116 * (just starting) 117 * 118 * @return boolean flag indicating if the state is initial (just starting) 119 */ 120 @Override 121 public boolean isInitial() { 122 return init; 123 } 124 125 /** 126 * Display state for debugging purposes 127 */ 128 @Override 129 public String toString() { 130 StringBuilder sb = new StringBuilder(); 131 sb.append("State ["); 132 sb.append("\n subjectDN of last cert: ").append(subjectDN); 133 sb.append("\n subjectKeyIdentifier: ").append 134 (String.valueOf(subjKeyId)); 135 sb.append("\n nameConstraints: ").append(String.valueOf(nc)); 136 sb.append("\n certIndex: ").append(certIndex); 137 sb.append("\n explicitPolicy: ").append(explicitPolicy); 138 sb.append("\n policyMapping: ").append(policyMapping); 139 sb.append("\n inhibitAnyPolicy: ").append(inhibitAnyPolicy); 140 sb.append("\n rootNode: ").append(rootNode); 141 sb.append("\n remainingCACerts: ").append(remainingCACerts); 142 sb.append("\n crlSign: ").append(crlSign); 143 sb.append("\n init: ").append(init); 144 sb.append("\n]\n"); 145 return sb.toString(); 146 } 147 148 /** 149 * Initialize the state. 150 * 151 * @param buildParams builder parameters 152 */ 153 public void initState(BuilderParams buildParams) 154 throws CertPathValidatorException 155 { 156 /* 157 * Initialize number of remainingCACerts. 158 * Note that -1 maxPathLen implies unlimited. 159 * 0 implies only an EE cert is acceptable. 160 */ 161 int maxPathLen = buildParams.maxPathLength(); 162 remainingCACerts = (maxPathLen == -1) ? Integer.MAX_VALUE 163 : maxPathLen; 164 165 /* Initialize explicit policy state variable */ 166 if (buildParams.explicitPolicyRequired()) { 167 explicitPolicy = 0; 168 } else { 169 // unconstrained if maxPathLen is -1, 170 // otherwise, we want to initialize this to the value of the 171 // longest possible path + 1 (i.e. maxpathlen + finalcert + 1) 172 explicitPolicy = (maxPathLen == -1) ? maxPathLen : maxPathLen + 2; 173 } 174 175 /* Initialize policy mapping state variable */ 176 if (buildParams.policyMappingInhibited()) { 177 policyMapping = 0; 178 } else { 179 policyMapping = (maxPathLen == -1) ? maxPathLen : maxPathLen + 2; 180 } 181 182 /* Initialize inhibit any policy state variable */ 183 if (buildParams.anyPolicyInhibited()) { 184 inhibitAnyPolicy = 0; 185 } else { 186 inhibitAnyPolicy = (maxPathLen == -1) ? maxPathLen : maxPathLen + 2; 187 } 188 189 /* Initialize certIndex */ 190 certIndex = 1; 191 192 /* Initialize policy tree */ 193 Set<String> initExpPolSet = new HashSet<>(1); 194 initExpPolSet.add(PolicyChecker.ANY_POLICY); 195 196 rootNode = new PolicyNodeImpl(null, PolicyChecker.ANY_POLICY, null, 197 false, initExpPolSet, false); 198 199 /* 200 * Initialize each user-defined checker 201 * Shallow copy the checkers 202 */ 203 userCheckers = new ArrayList<>(buildParams.certPathCheckers()); 204 /* initialize each checker (just in case) */ 205 for (PKIXCertPathChecker checker : userCheckers) { 206 checker.init(false); 207 } 208 209 /* Start by trusting the cert to sign CRLs */ 210 crlSign = true; 211 212 init = true; 213 } 214 215 /** 216 * Update the state with the specified trust anchor. 217 * 218 * @param anchor the most-trusted CA 219 * @param buildParams builder parameters 220 */ 221 public void updateState(TrustAnchor anchor, BuilderParams buildParams) 222 throws CertificateException, IOException, CertPathValidatorException 223 { 224 trustAnchor = anchor; 225 X509Certificate trustedCert = anchor.getTrustedCert(); 226 if (trustedCert != null) { 227 updateState(trustedCert); 228 } else { 229 X500Principal caName = anchor.getCA(); 230 updateState(anchor.getCAPublicKey(), caName); 231 } 232 233 // The user specified AlgorithmChecker and RevocationChecker may not be 234 // able to set the trust anchor until now. 235 boolean revCheckerAdded = false; 236 for (PKIXCertPathChecker checker : userCheckers) { 237 if (checker instanceof AlgorithmChecker) { 238 ((AlgorithmChecker)checker).trySetTrustAnchor(anchor); 239 } else if (checker instanceof PKIXRevocationChecker) { 240 if (revCheckerAdded) { 241 throw new CertPathValidatorException( 242 "Only one PKIXRevocationChecker can be specified"); 243 } 244 // if it's our own, initialize it 245 if (checker instanceof RevocationChecker) { 246 ((RevocationChecker)checker).init(anchor, buildParams); 247 } 248 ((PKIXRevocationChecker)checker).init(false); 249 revCheckerAdded = true; 250 } 251 } 252 253 // only create a RevocationChecker if revocation is enabled and 254 // a PKIXRevocationChecker has not already been added 255 if (buildParams.revocationEnabled() && !revCheckerAdded) { 256 revChecker = new RevocationChecker(anchor, buildParams); 257 revChecker.init(false); 258 } 259 260 init = false; 261 } 262 263 /** 264 * Update the state. This method is used when the most-trusted CA is 265 * a trusted public-key and caName, instead of a trusted cert. 266 * 267 * @param pubKey the public key of the trusted CA 268 * @param subjectDN the subject distinguished name of the trusted CA 269 */ 270 private void updateState(PublicKey pubKey, X500Principal subjectDN) { 271 272 /* update subject DN */ 273 this.subjectDN = subjectDN; 274 275 /* update subject public key */ 276 this.pubKey = pubKey; 277 } 278 279 /** 280 * Update the state with the next certificate added to the path. 281 * 282 * @param cert the certificate which is used to update the state 283 */ 284 public void updateState(X509Certificate cert) 285 throws CertificateException, IOException, CertPathValidatorException { 286 287 if (cert == null) { 288 return; 289 } 290 291 /* update subject DN */ 292 subjectDN = cert.getSubjectX500Principal(); 293 294 /* check for key needing to inherit alg parameters */ 295 X509CertImpl icert = X509CertImpl.toImpl(cert); 296 PublicKey newKey = cert.getPublicKey(); 297 if (PKIX.isDSAPublicKeyWithoutParams(newKey)) { 298 newKey = BasicChecker.makeInheritedParamsKey(newKey, pubKey); 299 } 300 301 /* update subject public key */ 302 pubKey = newKey; 303 304 /* 305 * if this is a trusted cert (init == true), then we 306 * don't update any of the remaining fields 307 */ 308 if (init) { 309 init = false; 310 return; 311 } 312 313 /* update subject key identifier */ 314 subjKeyId = icert.getSubjectKeyIdentifierExtension(); 315 316 /* update crlSign */ 317 crlSign = RevocationChecker.certCanSignCrl(cert); 318 319 /* update current name constraints */ 320 if (nc != null) { 321 nc.merge(icert.getNameConstraintsExtension()); 322 } else { 323 nc = icert.getNameConstraintsExtension(); 324 if (nc != null) { 325 // Make sure we do a clone here, because we're probably 326 // going to modify this object later and we don't want to 327 // be sharing it with a Certificate object! 328 nc = (NameConstraintsExtension) nc.clone(); 329 } 330 } 331 332 /* update policy state variables */ 333 explicitPolicy = 334 PolicyChecker.mergeExplicitPolicy(explicitPolicy, icert, false); 335 policyMapping = 336 PolicyChecker.mergePolicyMapping(policyMapping, icert); 337 inhibitAnyPolicy = 338 PolicyChecker.mergeInhibitAnyPolicy(inhibitAnyPolicy, icert); 339 certIndex++; 340 341 /* 342 * Update remaining CA certs 343 */ 344 remainingCACerts = 345 ConstraintsChecker.mergeBasicConstraints(cert, remainingCACerts); 346 347 init = false; 348 } 349 350 /** 351 * Returns a boolean flag indicating if a key lacking necessary key 352 * algorithm parameters has been encountered. 353 * 354 * @return boolean flag indicating if key lacking parameters encountered. 355 */ 356 @Override 357 public boolean keyParamsNeeded() { 358 /* when building in reverse, we immediately get parameters needed 359 * or else throw an exception 360 */ 361 return false; 362 } 363 364 /* 365 * Clone current state. The state is cloned as each cert is 366 * added to the path. This is necessary if backtracking occurs, 367 * and a prior state needs to be restored. 368 * 369 * Note that this is a SMART clone. Not all fields are fully copied, 370 * because some of them (e.g., subjKeyId) will 371 * not have their contents modified by subsequent calls to updateState. 372 */ 373 @Override 374 @SuppressWarnings("unchecked") // Safe casts assuming clone() works correctly 375 public Object clone() { 376 try { 377 ReverseState clonedState = (ReverseState) super.clone(); 378 379 /* clone checkers, if cloneable */ 380 clonedState.userCheckers = 381 (ArrayList<PKIXCertPathChecker>)userCheckers.clone(); 382 ListIterator<PKIXCertPathChecker> li = 383 clonedState.userCheckers.listIterator(); 384 while (li.hasNext()) { 385 PKIXCertPathChecker checker = li.next(); 386 if (checker instanceof Cloneable) { 387 li.set((PKIXCertPathChecker)checker.clone()); 388 } 389 } 390 391 /* make copy of name constraints */ 392 if (nc != null) { 393 clonedState.nc = (NameConstraintsExtension) nc.clone(); 394 } 395 396 /* make copy of policy tree */ 397 if (rootNode != null) { 398 clonedState.rootNode = rootNode.copyTree(); 399 } 400 401 return clonedState; 402 } catch (CloneNotSupportedException e) { 403 throw new InternalError(e.toString(), e); 404 } 405 } 406 } 407