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