1 /* 2 * Copyright (c) 2000, 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 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.X509Certificate; 34 import java.security.interfaces.DSAPublicKey; 35 import java.util.ArrayList; 36 import java.util.HashSet; 37 import java.util.Iterator; 38 import java.util.List; 39 import java.util.ListIterator; 40 import javax.security.auth.x500.X500Principal; 41 42 import sun.security.util.Debug; 43 import sun.security.x509.SubjectAlternativeNameExtension; 44 import sun.security.x509.GeneralNames; 45 import sun.security.x509.GeneralName; 46 import sun.security.x509.GeneralNameInterface; 47 import sun.security.x509.X500Name; 48 import sun.security.x509.X509CertImpl; 49 50 /** 51 * A specification of a forward PKIX validation state 52 * which is initialized by each build and updated each time a 53 * certificate is added to the current path. 54 * @since 1.4 55 * @author Yassir Elley 56 */ 57 class ForwardState implements State { 58 59 private static final Debug debug = Debug.getInstance("certpath"); 60 61 /* The issuer DN of the last cert in the path */ 62 X500Principal issuerDN; 63 64 /* The last cert in the path */ 65 X509CertImpl cert; 66 67 /* The set of subjectDNs and subjectAltNames of all certs in the path */ 68 HashSet<GeneralNameInterface> subjectNamesTraversed; 69 70 /* 71 * The number of intermediate CA certs which have been traversed so 72 * far in the path 73 */ 74 int traversedCACerts; 75 76 /* Flag indicating if state is initial (path is just starting) */ 77 private boolean init = true; 78 79 /* the checker used for revocation status */ 80 public CrlRevocationChecker crlChecker; 81 82 /* the untrusted certificates checker */ 83 UntrustedChecker untrustedChecker; 84 85 /* The list of user-defined checkers that support forward checking */ 86 ArrayList<PKIXCertPathChecker> forwardCheckers; 87 88 /* Flag indicating if key needing to inherit key parameters has been 89 * encountered. 90 */ 91 boolean keyParamsNeededFlag = false; 92 93 /** 94 * Returns a boolean flag indicating if the state is initial 95 * (just starting) 96 * 97 * @return boolean flag indicating if the state is initial (just starting) 98 */ 99 public boolean isInitial() { 100 return init; 101 } 102 103 /** 104 * Return boolean flag indicating whether a public key that needs to inherit 105 * key parameters has been encountered. 106 * 107 * @return boolean true if key needing to inherit parameters has been 108 * encountered; false otherwise. 109 */ 110 public boolean keyParamsNeeded() { 111 return keyParamsNeededFlag; 112 } 113 114 /** 115 * Display state for debugging purposes 116 */ 117 public String toString() { 118 StringBuffer sb = new StringBuffer(); 119 try { 120 sb.append("State ["); 121 sb.append("\n issuerDN of last cert: " + issuerDN); 122 sb.append("\n traversedCACerts: " + traversedCACerts); 123 sb.append("\n init: " + String.valueOf(init)); 124 sb.append("\n keyParamsNeeded: " 125 + String.valueOf(keyParamsNeededFlag)); 126 sb.append("\n subjectNamesTraversed: \n" + subjectNamesTraversed); 127 sb.append("]\n"); 128 } catch (Exception e) { 129 if (debug != null) { 130 debug.println("ForwardState.toString() unexpected exception"); 131 e.printStackTrace(); 132 } 133 } 134 return sb.toString(); 135 } 136 137 /** 138 * Initialize the state. 139 * 140 * @param certPathCheckers the list of user-defined PKIXCertPathCheckers 141 */ 142 public void initState(List<PKIXCertPathChecker> certPathCheckers) 143 throws CertPathValidatorException 144 { 145 subjectNamesTraversed = new HashSet<GeneralNameInterface>(); 146 traversedCACerts = 0; 147 148 /* 149 * Populate forwardCheckers with every user-defined checker 150 * that supports forward checking and initialize the forwardCheckers 151 */ 152 forwardCheckers = new ArrayList<PKIXCertPathChecker>(); 153 if (certPathCheckers != null) { 154 for (PKIXCertPathChecker checker : certPathCheckers) { 155 if (checker.isForwardCheckingSupported()) { 156 checker.init(true); 157 forwardCheckers.add(checker); 158 } 159 } 160 } 161 162 init = true; 163 } 164 165 /** 166 * Update the state with the next certificate added to the path. 167 * 168 * @param cert the certificate which is used to update the state 169 */ 170 public void updateState(X509Certificate cert) 171 throws CertificateException, IOException, CertPathValidatorException { 172 173 if (cert == null) 174 return; 175 176 X509CertImpl icert = X509CertImpl.toImpl(cert); 177 178 /* see if certificate key has null parameters */ 179 PublicKey newKey = icert.getPublicKey(); 180 if (newKey instanceof DSAPublicKey && 181 ((DSAPublicKey)newKey).getParams() == null) { 182 keyParamsNeededFlag = true; 183 } 184 185 /* update certificate */ 186 this.cert = icert; 187 188 /* update issuer DN */ 189 issuerDN = cert.getIssuerX500Principal(); 190 191 if (!X509CertImpl.isSelfIssued(cert)) { 192 193 /* 194 * update traversedCACerts only if this is a non-self-issued 195 * intermediate CA cert 196 */ 197 if (!init && cert.getBasicConstraints() != -1) { 198 traversedCACerts++; 199 } 200 } 201 202 /* update subjectNamesTraversed only if this is the EE cert or if 203 this cert is not self-issued */ 204 if (init || !X509CertImpl.isSelfIssued(cert)){ 205 X500Principal subjName = cert.getSubjectX500Principal(); 206 subjectNamesTraversed.add(X500Name.asX500Name(subjName)); 207 208 try { 209 SubjectAlternativeNameExtension subjAltNameExt 210 = icert.getSubjectAlternativeNameExtension(); 211 if (subjAltNameExt != null) { 212 GeneralNames gNames = (GeneralNames) 213 subjAltNameExt.get(SubjectAlternativeNameExtension.SUBJECT_NAME); 214 for (Iterator<GeneralName> t = gNames.iterator(); 215 t.hasNext(); ) { 216 GeneralNameInterface gName = t.next().getName(); 217 subjectNamesTraversed.add(gName); 218 } 219 } 220 } catch (Exception e) { 221 if (debug != null) { 222 debug.println("ForwardState.updateState() unexpected " 223 + "exception"); 224 e.printStackTrace(); 225 } 226 throw new CertPathValidatorException(e); 227 } 228 } 229 230 init = false; 231 } 232 233 /* 234 * Clone current state. The state is cloned as each cert is 235 * added to the path. This is necessary if backtracking occurs, 236 * and a prior state needs to be restored. 237 * 238 * Note that this is a SMART clone. Not all fields are fully copied, 239 * because some of them will 240 * not have their contents modified by subsequent calls to updateState. 241 */ 242 public Object clone() { 243 try { 244 ForwardState clonedState = (ForwardState) super.clone(); 245 246 /* clone checkers, if cloneable */ 247 clonedState.forwardCheckers = (ArrayList<PKIXCertPathChecker>) 248 forwardCheckers.clone(); 249 ListIterator<PKIXCertPathChecker> li = 250 clonedState.forwardCheckers.listIterator(); 251 while (li.hasNext()) { 252 PKIXCertPathChecker checker = li.next(); 253 if (checker instanceof Cloneable) { 254 li.set((PKIXCertPathChecker)checker.clone()); 255 } 256 } 257 258 /* 259 * Shallow copy traversed names. There is no need to 260 * deep copy contents, since the elements of the Set 261 * are never modified by subsequent calls to updateState(). 262 */ 263 clonedState.subjectNamesTraversed 264 = (HashSet<GeneralNameInterface>)subjectNamesTraversed.clone(); 265 return clonedState; 266 } catch (CloneNotSupportedException e) { 267 throw new InternalError(e.toString()); 268 } 269 } 270 }