/** * Returns true if a custom (not com.sun.security.auth.PolicyFile) system-wide policy object has * been set or installed. This method is called by SubjectDomainCombiner to provide backwards * compatibility for developers that provide their own javax.security.auth.Policy implementations. * * @return true if a custom (not com.sun.security.auth.PolicyFile) system-wide policy object has * been set; false otherwise */ static boolean isCustomPolicySet(Debug debug) { if (policy != null) { if (debug != null && isCustomPolicy) { debug.println( "Providing backwards compatibility for " + "javax.security.auth.policy implementation: " + policy.toString()); } return isCustomPolicy; } // check if custom policy has been set using auth.policy.provider prop String policyClass = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<String>() { public String run() { return Security.getProperty("auth.policy.provider"); } }); if (policyClass != null && !policyClass.equals("com.sun.security.auth.PolicyFile")) { if (debug != null) { debug.println( "Providing backwards compatibility for " + "javax.security.auth.policy implementation: " + policyClass); } return true; } return false; }
private PKIXCertPathBuilderResult buildCertPath( boolean searchAllCertStores, List<List<Vertex>> adjList) throws CertPathBuilderException { // Init shared variables and build certification path pathCompleted = false; trustAnchor = null; finalPublicKey = null; policyTreeResult = null; LinkedList<X509Certificate> certPathList = new LinkedList<>(); try { buildForward(adjList, certPathList, searchAllCertStores); } catch (GeneralSecurityException | IOException e) { if (debug != null) { debug.println("SunCertPathBuilder.engineBuild() exception in " + "build"); e.printStackTrace(); } throw new SunCertPathBuilderException( "unable to find valid " + "certification path to requested target", e, new AdjacencyList(adjList)); } // construct SunCertPathBuilderResult try { if (pathCompleted) { if (debug != null) debug.println("SunCertPathBuilder.engineBuild() " + "pathCompleted"); // we must return a certpath which has the target // as the first cert in the certpath - i.e. reverse // the certPathList Collections.reverse(certPathList); return new SunCertPathBuilderResult( cf.generateCertPath(certPathList), trustAnchor, policyTreeResult, finalPublicKey, new AdjacencyList(adjList)); } } catch (CertificateException e) { if (debug != null) { debug.println("SunCertPathBuilder.engineBuild() exception " + "in wrap-up"); e.printStackTrace(); } throw new SunCertPathBuilderException( "unable to find valid " + "certification path to requested target", e, new AdjacencyList(adjList)); } return null; }
/** Get the provider object. Loads the provider if it is not already loaded. */ synchronized Provider getProvider() { // volatile variable load Provider p = provider; if (p != null) { return p; } if (shouldLoad() == false) { return null; } if (isLoading) { // because this method is synchronized, this can only // happen if there is recursion. if (debug != null) { debug.println("Recursion loading provider: " + this); new Exception("Call trace").printStackTrace(); } return null; } try { isLoading = true; tries++; p = doLoadProvider(); } finally { isLoading = false; } provider = p; return p; }
/* * Private build forward method. */ private void buildForward( List<List<Vertex>> adjacencyList, LinkedList<X509Certificate> certPathList, boolean searchAllCertStores) throws GeneralSecurityException, IOException { if (debug != null) { debug.println("SunCertPathBuilder.buildForward()..."); } /* Initialize current state */ ForwardState currentState = new ForwardState(); currentState.initState(buildParams.certPathCheckers()); /* Initialize adjacency list */ adjacencyList.clear(); adjacencyList.add(new LinkedList<Vertex>()); currentState.untrustedChecker = new UntrustedChecker(); depthFirstSearchForward( buildParams.targetSubject(), currentState, new ForwardBuilder(buildParams, searchAllCertStores), adjacencyList, certPathList); }
private AccessControlContext goCombiner( ProtectionDomain[] current, AccessControlContext assigned) { // the assigned ACC's combiner is not null -- // let the combiner do its thing // XXX we could add optimizations to 'current' here ... if (getDebug() != null) { debug.println("AccessControlContext invoking the Combiner"); } // No need to clone current and assigned.context // combine() will not update them ProtectionDomain[] combinedPds = assigned.combiner.combine(current, assigned.context); // return new AccessControlContext(combinedPds, assigned.combiner); // Reuse existing ACC this.context = combinedPds; this.combiner = assigned.combiner; this.isPrivileged = false; return this; }
/* * Retrieves all CA certificates which satisfy constraints * and requirements specified in the parameters and PKIX state. */ private Collection getMatchingCACerts(ReverseState currentState) throws CertificateException, CertStoreException, IOException { /* * Compose a CertSelector to filter out * certs which do not satisfy requirements. */ X509CertSelector sel = new X509CertSelector(); /* * Match on issuer (subject of previous cert) */ CertPathHelper.setIssuer(sel, currentState.subjectDN); /* * Match on certificate validity date. */ sel.setCertificateValid(date); /* * Match on target subject name (checks that current cert's * name constraints permit it to certify target). * (4 is the integer type for DIRECTORY name). */ sel.addPathToName(4, targetCertSelector.getSubjectAsBytes()); /* * Policy processing optimizations */ if (currentState.explicitPolicy == 0) sel.setPolicy(getMatchingPolicies()); /* * If previous cert has a subject key identifier extension, * use it to match on authority key identifier extension. */ /*if (currentState.subjKeyId != null) { AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension( (KeyIdentifier) currentState.subjKeyId.get(SubjectKeyIdentifierExtension.KEY_ID), null, null); sel.setAuthorityKeyIdentifier(authKeyId.getExtensionValue()); }*/ /* * Require CA certs */ sel.setBasicConstraints(0); /* Retrieve matching certs from CertStores */ ArrayList reverseCerts = new ArrayList(); addMatchingCerts(sel, buildParams.getCertStores(), reverseCerts); /* Sort remaining certs using name constraints */ Collections.sort(reverseCerts, new PKIXCertComparator()); if (debug != null) debug.println("ReverseBuilder.getMatchingCACerts got " + reverseCerts.size() + " certs."); return reverseCerts; }
/** Returns a printable representation of the CRLNumberExtension. */ public String toString() { String s = super.toString() + extensionLabel + ": " + ((crlNumber == null) ? "" : Debug.toHexString(crlNumber)) + "\n"; return (s); }
static Debug getDebug() { if (debugInit) return debug; else { if (Policy.isSet()) { debug = Debug.getInstance("access"); debugInit = true; } return debug; } }
/* */ private boolean isWorthTrying( X509Certificate paramX509Certificate1, X509Certificate paramX509Certificate2) /* */ { /* 220 */ boolean bool = false; /* */ /* 222 */ if (debug != null) { /* 223 */ debug.println( "PKIXCertPathValidator.isWorthTrying() checking if this trusted cert is worth trying ..."); /* */ } /* */ /* 227 */ if (paramX509Certificate2 == null) { /* 228 */ return true; /* */ } /* */ /* 231 */ AdaptableX509CertSelector localAdaptableX509CertSelector = new AdaptableX509CertSelector(); /* */ /* 235 */ localAdaptableX509CertSelector.setSubject( paramX509Certificate2.getIssuerX500Principal()); /* */ /* 238 */ localAdaptableX509CertSelector.setValidityPeriod( paramX509Certificate2.getNotBefore(), paramX509Certificate2.getNotAfter()); /* */ try /* */ { /* 246 */ X509CertImpl localX509CertImpl = X509CertImpl.toImpl(paramX509Certificate2); /* 247 */ localAdaptableX509CertSelector.parseAuthorityKeyIdentifierExtension( localX509CertImpl.getAuthorityKeyIdentifierExtension()); /* */ /* 250 */ bool = localAdaptableX509CertSelector.match(paramX509Certificate1); /* */ } /* */ catch (Exception localException) /* */ { /* */ } /* 255 */ if (debug != null) { /* 256 */ if (bool) /* 257 */ debug.println("YES - try this trustedCert"); /* */ else { /* 259 */ debug.println("NO - don't try this trustedCert"); /* */ } /* */ } /* */ /* 263 */ return bool; /* */ }
/** * Attempts to build a certification path using the Sun build algorithm from a trusted anchor(s) * to a target subject, which must both be specified in the input parameter set. This method will * attempt to build in the forward direction: from the target to the CA. * * <p>The certification path that is constructed is validated according to the PKIX specification. * * @param params the parameter set for building a path. Must be an instance of <code> * PKIXBuilderParameters</code>. * @return a certification path builder result. * @exception CertPathBuilderException Exception thrown if builder is unable to build a complete * certification path from the trusted anchor(s) to the target subject. * @throws InvalidAlgorithmParameterException if the given parameters are inappropriate for this * certification path builder. */ @Override public CertPathBuilderResult engineBuild(CertPathParameters params) throws CertPathBuilderException, InvalidAlgorithmParameterException { if (debug != null) { debug.println("SunCertPathBuilder.engineBuild(" + params + ")"); } buildParams = PKIX.checkBuilderParams(params); return build(); }
public String toString() { String LINE_SEP = System.getProperty("line.separator"); StringBuffer strbuf = new StringBuffer( "SunJCE Diffie-Hellman Public Key:" + LINE_SEP + "y:" + LINE_SEP + Debug.toHexString(this.y) + LINE_SEP + "p:" + LINE_SEP + Debug.toHexString(this.p) + LINE_SEP + "g:" + LINE_SEP + Debug.toHexString(this.g)); if (this.l != 0) strbuf.append(LINE_SEP + "l:" + LINE_SEP + " " + this.l); return strbuf.toString(); }
/* * Retrieves all end-entity certificates which satisfy constraints * and requirements specified in the parameters and PKIX state. */ private Collection getMatchingEECerts(ReverseState currentState) throws CertStoreException, CertificateException, IOException { /* * Compose a CertSelector to filter out * certs which do not satisfy requirements. * * First, retrieve clone of current target cert constraints, * and then add more selection criteria based on current validation state. */ X509CertSelector sel = (X509CertSelector) buildParams.getTargetCertConstraints(); /* * Match on issuer (subject of previous cert) */ CertPathHelper.setIssuer(sel, currentState.subjectDN); /* * Match on certificate validity date. */ sel.setCertificateValid(date); /* * Policy processing optimizations */ if (currentState.explicitPolicy == 0) sel.setPolicy(getMatchingPolicies()); /* * If previous cert has a subject key identifier extension, * use it to match on authority key identifier extension. */ /*if (currentState.subjKeyId != null) { AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension( (KeyIdentifier) currentState.subjKeyId.get(SubjectKeyIdentifierExtension.KEY_ID), null, null); sel.setAuthorityKeyIdentifier(authKeyId.getExtensionValue()); }*/ /* * Require EE certs */ sel.setBasicConstraints(-2); /* Retrieve matching certs from CertStores */ HashSet eeCerts = new HashSet(); addMatchingCerts(sel, buildParams.getCertStores(), eeCerts); if (debug != null) { debug.println("ReverseBuilder.getMatchingEECerts got " + eeCerts.size() + " certs."); } return eeCerts; }
/* * Verify the signature of the OCSP response. * The responder's cert is implicitly trusted. */ private boolean verifySignature(X509Certificate cert) throws CertPathValidatorException { try { Signature respSignature = Signature.getInstance(sigAlgId.getName()); respSignature.initVerify(cert.getPublicKey()); respSignature.update(tbsResponseData); if (respSignature.verify(signature)) { if (debug != null) { debug.println("Verified signature of OCSP Response"); } return true; } else { if (debug != null) { debug.println("Error verifying signature of OCSP Response"); } return false; } } catch (InvalidKeyException | NoSuchAlgorithmException | SignatureException e) { throw new CertPathValidatorException(e); } }
/** * Retrieves all certs from a CertStore which satisfy the requirements specified in the parameters * and the current PKIX state (name constraints, policy constraints, etc). * * @param currentState the current state. Must be an instance of <code>ReverseState</code> */ Collection getMatchingCerts(State currState) throws CertStoreException, CertificateException, IOException { ReverseState currentState = (ReverseState) currState; if (debug != null) debug.println("In ReverseBuilder.getMatchingCerts."); /* * The last certificate could be an EE or a CA certificate * (we may be building a partial certification path or * establishing trust in a CA). * * Try the EE certs before the CA certs. It will be more * common to build a path to an end entity. */ Collection certs = getMatchingEECerts(currentState); certs.addAll(getMatchingCACerts(currentState)); return certs; }
/* * This inner class compares 2 PKIX certificates according to which * should be tried first when building a path to the target. For * now, the algorithm is to look at name constraints in each cert and those * which constrain the path closer to the target should be * ranked higher. Later, we may want to consider other components, * such as key identifiers. */ class PKIXCertComparator implements Comparator { private Debug debug = Debug.getInstance("certpath"); public int compare(Object o1, Object o2) { X509Certificate cert1 = (X509Certificate) o1; X509Certificate cert2 = (X509Certificate) o2; /* * if either cert certifies the target, always * put at head of list. */ if (cert1.getSubjectX500Principal().equals(targetSubjectDN)) { return -1; } if (cert2.getSubjectX500Principal().equals(targetSubjectDN)) { return 1; } int targetDist1; int targetDist2; try { X500Name targetSubjectName = X500Name.asX500Name(targetSubjectDN); targetDist1 = Builder.targetDistance(null, cert1, targetSubjectName); targetDist2 = Builder.targetDistance(null, cert2, targetSubjectName); } catch (IOException e) { if (debug != null) { debug.println("IOException in call to Builder.targetDistance"); e.printStackTrace(); } throw new ClassCastException("Invalid target subject distinguished name"); } if (targetDist1 == targetDist2) return 0; if (targetDist1 == -1) return 1; if (targetDist1 < targetDist2) return -1; return 1; } }
private PKIXCertPathBuilderResult build() throws CertPathBuilderException { List<List<Vertex>> adjList = new ArrayList<>(); PKIXCertPathBuilderResult result = buildCertPath(false, adjList); if (result == null) { if (debug != null) { debug.println( "SunCertPathBuilder.engineBuild: 2nd pass; " + "try building again searching all certstores"); } // try again adjList.clear(); result = buildCertPath(true, adjList); if (result == null) { throw new SunCertPathBuilderException( "unable to find valid " + "certification path to requested target", new AdjacencyList(adjList)); } } return result; }
/** * Determines whether the access request indicated by the specified permission should be allowed * or denied, based on the security policy currently in effect, and the context in this object. * The request is allowed only if every ProtectionDomain in the context implies the permission. * Otherwise the request is denied. * * <p>This method quietly returns if the access request is permitted, or throws a suitable * AccessControlException otherwise. * * @param perm the requested permission. * @exception AccessControlException if the specified permission is not permitted, based on the * current security policy and the context encapsulated by this object. * @exception NullPointerException if the permission to check for is null. */ public void checkPermission(Permission perm) throws AccessControlException { boolean dumpDebug = false; if (perm == null) { throw new NullPointerException("permission can't be null"); } if (getDebug() != null) { // If "codebase" is not specified, we dump the info by default. dumpDebug = !Debug.isOn("codebase="); if (!dumpDebug) { // If "codebase" is specified, only dump if the specified code // value is in the stack. for (int i = 0; context != null && i < context.length; i++) { if (context[i].getCodeSource() != null && context[i].getCodeSource().getLocation() != null && Debug.isOn("codebase=" + context[i].getCodeSource().getLocation().toString())) { dumpDebug = true; break; } } } dumpDebug &= !Debug.isOn("permission=") || Debug.isOn("permission=" + perm.getClass().getCanonicalName()); if (dumpDebug && Debug.isOn("stack")) { Thread.currentThread().dumpStack(); } if (dumpDebug && Debug.isOn("domain")) { if (context == null) { debug.println("domain (context is null)"); } else { for (int i = 0; i < context.length; i++) { debug.println("domain " + i + " " + context[i]); } } } } /* * iterate through the ProtectionDomains in the context. * Stop at the first one that doesn't allow the * requested permission (throwing an exception). * */ /* if ctxt is null, all we had on the stack were system domains, or the first domain was a Privileged system domain. This is to make the common case for system code very fast */ if (context == null) return; for (int i = 0; i < context.length; i++) { if (context[i] != null && !context[i].implies(perm)) { if (dumpDebug) { debug.println("access denied " + perm); } if (Debug.isOn("failure") && debug != null) { // Want to make sure this is always displayed for failure, // but do not want to display again if already displayed // above. if (!dumpDebug) { debug.println("access denied " + perm); } Thread.currentThread().dumpStack(); final ProtectionDomain pd = context[i]; final Debug db = debug; AccessController.doPrivileged( new PrivilegedAction<Void>() { public Void run() { db.println("domain that failed " + pd); return null; } }); } throw new AccessControlException("access denied " + perm, perm); } } // allow if all of them allowed access if (dumpDebug) { debug.println("access allowed " + perm); } return; }
private void invoke(String methodName) throws LoginException { // start at moduleIndex // - this can only be non-zero if methodName is LOGIN_METHOD for (int i = moduleIndex; i < moduleStack.length; i++, moduleIndex++) { try { int mIndex = 0; Method[] methods = null; if (moduleStack[i].module != null) { methods = moduleStack[i].module.getClass().getMethods(); } else { // instantiate the LoginModule // // Allow any object to be a LoginModule as long as it // conforms to the interface. Class<?> c = Class.forName(moduleStack[i].entry.getLoginModuleName(), true, contextClassLoader); Constructor<?> constructor = c.getConstructor(PARAMS); Object[] args = {}; moduleStack[i].module = constructor.newInstance(args); // call the LoginModule's initialize method methods = moduleStack[i].module.getClass().getMethods(); for (mIndex = 0; mIndex < methods.length; mIndex++) { if (methods[mIndex].getName().equals(INIT_METHOD)) { break; } } Object[] initArgs = {subject, callbackHandler, state, moduleStack[i].entry.getOptions()}; // invoke the LoginModule initialize method // // Throws ArrayIndexOutOfBoundsException if no such // method defined. May improve to use LoginException in // the future. methods[mIndex].invoke(moduleStack[i].module, initArgs); } // find the requested method in the LoginModule for (mIndex = 0; mIndex < methods.length; mIndex++) { if (methods[mIndex].getName().equals(methodName)) { break; } } // set up the arguments to be passed to the LoginModule method Object[] args = {}; // invoke the LoginModule method // // Throws ArrayIndexOutOfBoundsException if no such // method defined. May improve to use LoginException in // the future. boolean status = ((Boolean) methods[mIndex].invoke(moduleStack[i].module, args)).booleanValue(); if (status == true) { // if SUFFICIENT, return if no prior REQUIRED errors if (!methodName.equals(ABORT_METHOD) && !methodName.equals(LOGOUT_METHOD) && moduleStack[i].entry.getControlFlag() == AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT && firstRequiredError == null) { // clear state clearState(); if (debug != null) debug.println(methodName + " SUFFICIENT success"); return; } if (debug != null) debug.println(methodName + " success"); success = true; } else { if (debug != null) debug.println(methodName + " ignored"); } } catch (NoSuchMethodException nsme) { MessageFormat form = new MessageFormat( ResourcesMgr.getString( "unable.to.instantiate.LoginModule.module.because.it.does.not.provide.a.no.argument.constructor")); Object[] source = {moduleStack[i].entry.getLoginModuleName()}; throwException(null, new LoginException(form.format(source))); } catch (InstantiationException ie) { throwException( null, new LoginException( ResourcesMgr.getString("unable.to.instantiate.LoginModule.") + ie.getMessage())); } catch (ClassNotFoundException cnfe) { throwException( null, new LoginException( ResourcesMgr.getString("unable.to.find.LoginModule.class.") + cnfe.getMessage())); } catch (IllegalAccessException iae) { throwException( null, new LoginException( ResourcesMgr.getString("unable.to.access.LoginModule.") + iae.getMessage())); } catch (InvocationTargetException ite) { // failure cases LoginException le; if (ite.getCause() instanceof PendingException && methodName.equals(LOGIN_METHOD)) { // XXX // // if a module's LOGIN_METHOD threw a PendingException // then immediately throw it. // // when LoginContext is called again, // the module that threw the exception is invoked first // (the module list is not invoked from the start). // previously thrown exception state is still present. // // it is assumed that the module which threw // the exception can have its // LOGIN_METHOD invoked twice in a row // without any commit/abort in between. // // in all cases when LoginContext returns // (either via natural return or by throwing an exception) // we need to call clearState before returning. // the only time that is not true is in this case - // do not call throwException here. throw (PendingException) ite.getCause(); } else if (ite.getCause() instanceof LoginException) { le = (LoginException) ite.getCause(); } else if (ite.getCause() instanceof SecurityException) { // do not want privacy leak // (e.g., sensitive file path in exception msg) le = new LoginException("Security Exception"); le.initCause(new SecurityException()); if (debug != null) { debug.println( "original security exception with detail msg " + "replaced by new exception with empty detail msg"); debug.println("original security exception: " + ite.getCause().toString()); } } else { // capture an unexpected LoginModule exception java.io.StringWriter sw = new java.io.StringWriter(); ite.getCause().printStackTrace(new java.io.PrintWriter(sw)); sw.flush(); le = new LoginException(sw.toString()); } if (moduleStack[i].entry.getControlFlag() == AppConfigurationEntry.LoginModuleControlFlag.REQUISITE) { if (debug != null) debug.println(methodName + " REQUISITE failure"); // if REQUISITE, then immediately throw an exception if (methodName.equals(ABORT_METHOD) || methodName.equals(LOGOUT_METHOD)) { if (firstRequiredError == null) firstRequiredError = le; } else { throwException(firstRequiredError, le); } } else if (moduleStack[i].entry.getControlFlag() == AppConfigurationEntry.LoginModuleControlFlag.REQUIRED) { if (debug != null) debug.println(methodName + " REQUIRED failure"); // mark down that a REQUIRED module failed if (firstRequiredError == null) firstRequiredError = le; } else { if (debug != null) debug.println(methodName + " OPTIONAL failure"); // mark down that an OPTIONAL module failed if (firstError == null) firstError = le; } } } // we went thru all the LoginModules. if (firstRequiredError != null) { // a REQUIRED module failed -- return the error throwException(firstRequiredError, null); } else if (success == false && firstError != null) { // no module succeeded -- return the first error throwException(firstError, null); } else if (success == false) { // no module succeeded -- all modules were IGNORED throwException( new LoginException(ResourcesMgr.getString("Login.Failure.all.modules.ignored")), null); } else { // success clearState(); return; } }
/** * The {@code LoginContext} class describes the basic methods used to authenticate Subjects and * provides a way to develop an application independent of the underlying authentication technology. * A {@code Configuration} specifies the authentication technology, or {@code LoginModule}, to be * used with a particular application. Different LoginModules can be plugged in under an application * without requiring any modifications to the application itself. * * <p>In addition to supporting <i>pluggable</i> authentication, this class also supports the notion * of <i>stacked</i> authentication. Applications may be configured to use more than one * LoginModule. For example, one could configure both a Kerberos LoginModule and a smart card * LoginModule under an application. * * <p>A typical caller instantiates a LoginContext with a <i>name</i> and a {@code CallbackHandler}. * LoginContext uses the <i>name</i> as the index into a Configuration to determine which * LoginModules should be used, and which ones must succeed in order for the overall authentication * to succeed. The {@code CallbackHandler} is passed to the underlying LoginModules so they may * communicate and interact with users (prompting for a username and password via a graphical user * interface, for example). * * <p>Once the caller has instantiated a LoginContext, it invokes the {@code login} method to * authenticate a {@code Subject}. The {@code login} method invokes the configured modules to * perform their respective types of authentication (username/password, smart card pin verification, * etc.). Note that the LoginModules will not attempt authentication retries nor introduce delays if * the authentication fails. Such tasks belong to the LoginContext caller. * * <p>If the {@code login} method returns without throwing an exception, then the overall * authentication succeeded. The caller can then retrieve the newly authenticated Subject by * invoking the {@code getSubject} method. Principals and Credentials associated with the Subject * may be retrieved by invoking the Subject's respective {@code getPrincipals}, {@code * getPublicCredentials}, and {@code getPrivateCredentials} methods. * * <p>To logout the Subject, the caller calls the {@code logout} method. As with the {@code login} * method, this {@code logout} method invokes the {@code logout} method for the configured modules. * * <p>A LoginContext should not be used to authenticate more than one Subject. A separate * LoginContext should be used to authenticate each different Subject. * * <p>The following documentation applies to all LoginContext constructors: * * <ol> * <li>{@code Subject} * <ul> * <li>If the constructor has a Subject input parameter, the LoginContext uses the * caller-specified Subject object. * <li>If the caller specifies a {@code null} Subject and a {@code null} value is permitted, * the LoginContext instantiates a new Subject. * <li>If the constructor does <b>not</b> have a Subject input parameter, the LoginContext * instantiates a new Subject. * <p> * </ul> * <li>{@code Configuration} * <ul> * <li>If the constructor has a Configuration input parameter and the caller specifies a * non-null Configuration, the LoginContext uses the caller-specified Configuration. * <p>If the constructor does <b>not</b> have a Configuration input parameter, or if the * caller specifies a {@code null} Configuration object, the constructor uses the * following call to get the installed Configuration: * <pre> * config = Configuration.getConfiguration(); * </pre> * For both cases, the <i>name</i> argument given to the constructor is passed to the * {@code Configuration.getAppConfigurationEntry} method. If the Configuration has no * entries for the specified <i>name</i>, then the {@code LoginContext} calls {@code * getAppConfigurationEntry} with the name, "<i>other</i>" (the default entry name). If * there is no entry for "<i>other</i>", then a {@code LoginException} is thrown. * <li>When LoginContext uses the installed Configuration, the caller requires the * createLoginContext.<em>name</em> and possibly createLoginContext.other * AuthPermissions. Furthermore, the LoginContext will invoke configured modules from * within an {@code AccessController.doPrivileged} call so that modules that perform * security-sensitive tasks (such as connecting to remote hosts, and updating the * Subject) will require the respective permissions, but the callers of the LoginContext * will not require those permissions. * <li>When LoginContext uses a caller-specified Configuration, the caller does not require * any createLoginContext AuthPermission. The LoginContext saves the {@code * AccessControlContext} for the caller, and invokes the configured modules from within * an {@code AccessController.doPrivileged} call constrained by that context. This means * the caller context (stored when the LoginContext was created) must have sufficient * permissions to perform any security-sensitive tasks that the modules may perform. * <p> * </ul> * <li>{@code CallbackHandler} * <ul> * <li>If the constructor has a CallbackHandler input parameter, the LoginContext uses the * caller-specified CallbackHandler object. * <li>If the constructor does <b>not</b> have a CallbackHandler input parameter, or if the * caller specifies a {@code null} CallbackHandler object (and a {@code null} value is * permitted), the LoginContext queries the {@code auth.login.defaultCallbackHandler} * security property for the fully qualified class name of a default handler * implementation. If the security property is not set, then the underlying modules will * not have a CallbackHandler for use in communicating with users. The caller thus * assumes that the configured modules have alternative means for authenticating the * user. * <li>When the LoginContext uses the installed Configuration (instead of a caller-specified * Configuration, see above), then this LoginContext must wrap any caller-specified or * default CallbackHandler implementation in a new CallbackHandler implementation whose * {@code handle} method implementation invokes the specified CallbackHandler's {@code * handle} method in a {@code java.security.AccessController.doPrivileged} call * constrained by the caller's current {@code AccessControlContext}. * </ul> * </ol> * * @see java.security.Security * @see javax.security.auth.AuthPermission * @see javax.security.auth.Subject * @see javax.security.auth.callback.CallbackHandler * @see javax.security.auth.login.Configuration * @see javax.security.auth.spi.LoginModule * @see java.security.Security security properties */ public class LoginContext { private static final String INIT_METHOD = "initialize"; private static final String LOGIN_METHOD = "login"; private static final String COMMIT_METHOD = "commit"; private static final String ABORT_METHOD = "abort"; private static final String LOGOUT_METHOD = "logout"; private static final String OTHER = "other"; private static final String DEFAULT_HANDLER = "auth.login.defaultCallbackHandler"; private Subject subject = null; private boolean subjectProvided = false; private boolean loginSucceeded = false; private CallbackHandler callbackHandler; private Map<String, ?> state = new HashMap<String, Object>(); private Configuration config; private AccessControlContext creatorAcc = null; // customized config only private ModuleInfo[] moduleStack; private ClassLoader contextClassLoader = null; private static final Class<?>[] PARAMS = {}; // state saved in the event a user-specified asynchronous exception // was specified and thrown private int moduleIndex = 0; private LoginException firstError = null; private LoginException firstRequiredError = null; private boolean success = false; private static final sun.security.util.Debug debug = sun.security.util.Debug.getInstance("logincontext", "\t[LoginContext]"); private void init(String name) throws LoginException { SecurityManager sm = System.getSecurityManager(); if (sm != null && creatorAcc == null) { sm.checkPermission(new AuthPermission("createLoginContext." + name)); } if (name == null) throw new LoginException(ResourcesMgr.getString("Invalid.null.input.name")); // get the Configuration if (config == null) { config = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Configuration>() { public Configuration run() { return Configuration.getConfiguration(); } }); } // get the LoginModules configured for this application AppConfigurationEntry[] entries = config.getAppConfigurationEntry(name); if (entries == null) { if (sm != null && creatorAcc == null) { sm.checkPermission(new AuthPermission("createLoginContext." + OTHER)); } entries = config.getAppConfigurationEntry(OTHER); if (entries == null) { MessageFormat form = new MessageFormat(ResourcesMgr.getString("No.LoginModules.configured.for.name")); Object[] source = {name}; throw new LoginException(form.format(source)); } } moduleStack = new ModuleInfo[entries.length]; for (int i = 0; i < entries.length; i++) { // clone returned array moduleStack[i] = new ModuleInfo( new AppConfigurationEntry( entries[i].getLoginModuleName(), entries[i].getControlFlag(), entries[i].getOptions()), null); } contextClassLoader = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<ClassLoader>() { public ClassLoader run() { ClassLoader loader = Thread.currentThread().getContextClassLoader(); if (loader == null) { // Don't use bootstrap class loader directly to ensure // proper package access control! loader = ClassLoader.getSystemClassLoader(); } return loader; } }); } private void loadDefaultCallbackHandler() throws LoginException { // get the default handler class try { final ClassLoader finalLoader = contextClassLoader; this.callbackHandler = java.security.AccessController.doPrivileged( new java.security.PrivilegedExceptionAction<CallbackHandler>() { public CallbackHandler run() throws Exception { String defaultHandler = java.security.Security.getProperty(DEFAULT_HANDLER); if (defaultHandler == null || defaultHandler.length() == 0) return null; Class<? extends CallbackHandler> c = Class.forName(defaultHandler, true, finalLoader) .asSubclass(CallbackHandler.class); return c.newInstance(); } }); } catch (java.security.PrivilegedActionException pae) { throw new LoginException(pae.getException().toString()); } // secure it with the caller's ACC if (this.callbackHandler != null && creatorAcc == null) { this.callbackHandler = new SecureCallbackHandler( java.security.AccessController.getContext(), this.callbackHandler); } } /** * Instantiate a new {@code LoginContext} object with a name. * * @param name the name used as the index into the {@code Configuration}. * @exception LoginException if the caller-specified {@code name} does not appear in the {@code * Configuration} and there is no {@code Configuration} entry for "<i>other</i>", or if the * <i>auth.login.defaultCallbackHandler</i> security property was set, but the implementation * class could not be loaded. * <p> * @exception SecurityException if a SecurityManager is set and the caller does not have * AuthPermission("createLoginContext.<i>name</i>"), or if a configuration entry for * <i>name</i> does not exist and the caller does not additionally have * AuthPermission("createLoginContext.other") */ public LoginContext(String name) throws LoginException { init(name); loadDefaultCallbackHandler(); } /** * Instantiate a new {@code LoginContext} object with a name and a {@code Subject} object. * * <p> * * @param name the name used as the index into the {@code Configuration}. * <p> * @param subject the {@code Subject} to authenticate. * @exception LoginException if the caller-specified {@code name} does not appear in the {@code * Configuration} and there is no {@code Configuration} entry for "<i>other</i>", if the * caller-specified {@code subject} is {@code null}, or if the * <i>auth.login.defaultCallbackHandler</i> security property was set, but the implementation * class could not be loaded. * <p> * @exception SecurityException if a SecurityManager is set and the caller does not have * AuthPermission("createLoginContext.<i>name</i>"), or if a configuration entry for * <i>name</i> does not exist and the caller does not additionally have * AuthPermission("createLoginContext.other") */ public LoginContext(String name, Subject subject) throws LoginException { init(name); if (subject == null) throw new LoginException(ResourcesMgr.getString("invalid.null.Subject.provided")); this.subject = subject; subjectProvided = true; loadDefaultCallbackHandler(); } /** * Instantiate a new {@code LoginContext} object with a name and a {@code CallbackHandler} object. * * <p> * * @param name the name used as the index into the {@code Configuration}. * <p> * @param callbackHandler the {@code CallbackHandler} object used by LoginModules to communicate * with the user. * @exception LoginException if the caller-specified {@code name} does not appear in the {@code * Configuration} and there is no {@code Configuration} entry for "<i>other</i>", or if the * caller-specified {@code callbackHandler} is {@code null}. * <p> * @exception SecurityException if a SecurityManager is set and the caller does not have * AuthPermission("createLoginContext.<i>name</i>"), or if a configuration entry for * <i>name</i> does not exist and the caller does not additionally have * AuthPermission("createLoginContext.other") */ public LoginContext(String name, CallbackHandler callbackHandler) throws LoginException { init(name); if (callbackHandler == null) throw new LoginException(ResourcesMgr.getString("invalid.null.CallbackHandler.provided")); this.callbackHandler = new SecureCallbackHandler(java.security.AccessController.getContext(), callbackHandler); } /** * Instantiate a new {@code LoginContext} object with a name, a {@code Subject} to be * authenticated, and a {@code CallbackHandler} object. * * <p> * * @param name the name used as the index into the {@code Configuration}. * <p> * @param subject the {@code Subject} to authenticate. * <p> * @param callbackHandler the {@code CallbackHandler} object used by LoginModules to communicate * with the user. * @exception LoginException if the caller-specified {@code name} does not appear in the {@code * Configuration} and there is no {@code Configuration} entry for "<i>other</i>", or if the * caller-specified {@code subject} is {@code null}, or if the caller-specified {@code * callbackHandler} is {@code null}. * <p> * @exception SecurityException if a SecurityManager is set and the caller does not have * AuthPermission("createLoginContext.<i>name</i>"), or if a configuration entry for * <i>name</i> does not exist and the caller does not additionally have * AuthPermission("createLoginContext.other") */ public LoginContext(String name, Subject subject, CallbackHandler callbackHandler) throws LoginException { this(name, subject); if (callbackHandler == null) throw new LoginException(ResourcesMgr.getString("invalid.null.CallbackHandler.provided")); this.callbackHandler = new SecureCallbackHandler(java.security.AccessController.getContext(), callbackHandler); } /** * Instantiate a new {@code LoginContext} object with a name, a {@code Subject} to be * authenticated, a {@code CallbackHandler} object, and a login {@code Configuration}. * * <p> * * @param name the name used as the index into the caller-specified {@code Configuration}. * <p> * @param subject the {@code Subject} to authenticate, or {@code null}. * <p> * @param callbackHandler the {@code CallbackHandler} object used by LoginModules to communicate * with the user, or {@code null}. * <p> * @param config the {@code Configuration} that lists the login modules to be called to perform * the authentication, or {@code null}. * @exception LoginException if the caller-specified {@code name} does not appear in the {@code * Configuration} and there is no {@code Configuration} entry for "<i>other</i>". * <p> * @exception SecurityException if a SecurityManager is set, <i>config</i> is {@code null}, and * either the caller does not have AuthPermission("createLoginContext.<i>name</i>"), or if a * configuration entry for <i>name</i> does not exist and the caller does not additionally * have AuthPermission("createLoginContext.other") * @since 1.5 */ public LoginContext( String name, Subject subject, CallbackHandler callbackHandler, Configuration config) throws LoginException { this.config = config; if (config != null) { creatorAcc = java.security.AccessController.getContext(); } init(name); if (subject != null) { this.subject = subject; subjectProvided = true; } if (callbackHandler == null) { loadDefaultCallbackHandler(); } else if (creatorAcc == null) { this.callbackHandler = new SecureCallbackHandler(java.security.AccessController.getContext(), callbackHandler); } else { this.callbackHandler = callbackHandler; } } /** * Perform the authentication. * * <p>This method invokes the {@code login} method for each LoginModule configured for the * <i>name</i> specified to the {@code LoginContext} constructor, as determined by the login * {@code Configuration}. Each {@code LoginModule} then performs its respective type of * authentication (username/password, smart card pin verification, etc.). * * <p>This method completes a 2-phase authentication process by calling each configured * LoginModule's {@code commit} method if the overall authentication succeeded (the relevant * REQUIRED, REQUISITE, SUFFICIENT, and OPTIONAL LoginModules succeeded), or by calling each * configured LoginModule's {@code abort} method if the overall authentication failed. If * authentication succeeded, each successful LoginModule's {@code commit} method associates the * relevant Principals and Credentials with the {@code Subject}. If authentication failed, each * LoginModule's {@code abort} method removes/destroys any previously stored state. * * <p>If the {@code commit} phase of the authentication process fails, then the overall * authentication fails and this method invokes the {@code abort} method for each configured * {@code LoginModule}. * * <p>If the {@code abort} phase fails for any reason, then this method propagates the original * exception thrown either during the {@code login} phase or the {@code commit} phase. In either * case, the overall authentication fails. * * <p>In the case where multiple LoginModules fail, this method propagates the exception raised by * the first {@code LoginModule} which failed. * * <p>Note that if this method enters the {@code abort} phase (either the {@code login} or {@code * commit} phase failed), this method invokes all LoginModules configured for the application * regardless of their respective {@code Configuration} flag parameters. Essentially this means * that {@code Requisite} and {@code Sufficient} semantics are ignored during the {@code abort} * phase. This guarantees that proper cleanup and state restoration can take place. * * <p> * * @exception LoginException if the authentication fails. */ public void login() throws LoginException { loginSucceeded = false; if (subject == null) { subject = new Subject(); } try { // module invoked in doPrivileged invokePriv(LOGIN_METHOD); invokePriv(COMMIT_METHOD); loginSucceeded = true; } catch (LoginException le) { try { invokePriv(ABORT_METHOD); } catch (LoginException le2) { throw le; } throw le; } } /** * Logout the {@code Subject}. * * <p>This method invokes the {@code logout} method for each {@code LoginModule} configured for * this {@code LoginContext}. Each {@code LoginModule} performs its respective logout procedure * which may include removing/destroying {@code Principal} and {@code Credential} information from * the {@code Subject} and state cleanup. * * <p>Note that this method invokes all LoginModules configured for the application regardless of * their respective {@code Configuration} flag parameters. Essentially this means that {@code * Requisite} and {@code Sufficient} semantics are ignored for this method. This guarantees that * proper cleanup and state restoration can take place. * * <p> * * @exception LoginException if the logout fails. */ public void logout() throws LoginException { if (subject == null) { throw new LoginException(ResourcesMgr.getString("null.subject.logout.called.before.login")); } // module invoked in doPrivileged invokePriv(LOGOUT_METHOD); } /** * Return the authenticated Subject. * * <p> * * @return the authenticated Subject. If the caller specified a Subject to this LoginContext's * constructor, this method returns the caller-specified Subject. If a Subject was not * specified and authentication succeeds, this method returns the Subject instantiated and * used for authentication by this LoginContext. If a Subject was not specified, and * authentication fails or has not been attempted, this method returns null. */ public Subject getSubject() { if (!loginSucceeded && !subjectProvided) return null; return subject; } private void clearState() { moduleIndex = 0; firstError = null; firstRequiredError = null; success = false; } private void throwException(LoginException originalError, LoginException le) throws LoginException { // first clear state clearState(); // throw the exception LoginException error = (originalError != null) ? originalError : le; throw error; } /** * Invokes the login, commit, and logout methods from a LoginModule inside a doPrivileged block * restricted by creatorAcc (may be null). * * <p>This version is called if the caller did not instantiate the LoginContext with a * Configuration object. */ private void invokePriv(final String methodName) throws LoginException { try { java.security.AccessController.doPrivileged( new java.security.PrivilegedExceptionAction<Void>() { public Void run() throws LoginException { invoke(methodName); return null; } }, creatorAcc); } catch (java.security.PrivilegedActionException pae) { throw (LoginException) pae.getException(); } } private void invoke(String methodName) throws LoginException { // start at moduleIndex // - this can only be non-zero if methodName is LOGIN_METHOD for (int i = moduleIndex; i < moduleStack.length; i++, moduleIndex++) { try { int mIndex = 0; Method[] methods = null; if (moduleStack[i].module != null) { methods = moduleStack[i].module.getClass().getMethods(); } else { // instantiate the LoginModule // // Allow any object to be a LoginModule as long as it // conforms to the interface. Class<?> c = Class.forName(moduleStack[i].entry.getLoginModuleName(), true, contextClassLoader); Constructor<?> constructor = c.getConstructor(PARAMS); Object[] args = {}; moduleStack[i].module = constructor.newInstance(args); // call the LoginModule's initialize method methods = moduleStack[i].module.getClass().getMethods(); for (mIndex = 0; mIndex < methods.length; mIndex++) { if (methods[mIndex].getName().equals(INIT_METHOD)) { break; } } Object[] initArgs = {subject, callbackHandler, state, moduleStack[i].entry.getOptions()}; // invoke the LoginModule initialize method // // Throws ArrayIndexOutOfBoundsException if no such // method defined. May improve to use LoginException in // the future. methods[mIndex].invoke(moduleStack[i].module, initArgs); } // find the requested method in the LoginModule for (mIndex = 0; mIndex < methods.length; mIndex++) { if (methods[mIndex].getName().equals(methodName)) { break; } } // set up the arguments to be passed to the LoginModule method Object[] args = {}; // invoke the LoginModule method // // Throws ArrayIndexOutOfBoundsException if no such // method defined. May improve to use LoginException in // the future. boolean status = ((Boolean) methods[mIndex].invoke(moduleStack[i].module, args)).booleanValue(); if (status == true) { // if SUFFICIENT, return if no prior REQUIRED errors if (!methodName.equals(ABORT_METHOD) && !methodName.equals(LOGOUT_METHOD) && moduleStack[i].entry.getControlFlag() == AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT && firstRequiredError == null) { // clear state clearState(); if (debug != null) debug.println(methodName + " SUFFICIENT success"); return; } if (debug != null) debug.println(methodName + " success"); success = true; } else { if (debug != null) debug.println(methodName + " ignored"); } } catch (NoSuchMethodException nsme) { MessageFormat form = new MessageFormat( ResourcesMgr.getString( "unable.to.instantiate.LoginModule.module.because.it.does.not.provide.a.no.argument.constructor")); Object[] source = {moduleStack[i].entry.getLoginModuleName()}; throwException(null, new LoginException(form.format(source))); } catch (InstantiationException ie) { throwException( null, new LoginException( ResourcesMgr.getString("unable.to.instantiate.LoginModule.") + ie.getMessage())); } catch (ClassNotFoundException cnfe) { throwException( null, new LoginException( ResourcesMgr.getString("unable.to.find.LoginModule.class.") + cnfe.getMessage())); } catch (IllegalAccessException iae) { throwException( null, new LoginException( ResourcesMgr.getString("unable.to.access.LoginModule.") + iae.getMessage())); } catch (InvocationTargetException ite) { // failure cases LoginException le; if (ite.getCause() instanceof PendingException && methodName.equals(LOGIN_METHOD)) { // XXX // // if a module's LOGIN_METHOD threw a PendingException // then immediately throw it. // // when LoginContext is called again, // the module that threw the exception is invoked first // (the module list is not invoked from the start). // previously thrown exception state is still present. // // it is assumed that the module which threw // the exception can have its // LOGIN_METHOD invoked twice in a row // without any commit/abort in between. // // in all cases when LoginContext returns // (either via natural return or by throwing an exception) // we need to call clearState before returning. // the only time that is not true is in this case - // do not call throwException here. throw (PendingException) ite.getCause(); } else if (ite.getCause() instanceof LoginException) { le = (LoginException) ite.getCause(); } else if (ite.getCause() instanceof SecurityException) { // do not want privacy leak // (e.g., sensitive file path in exception msg) le = new LoginException("Security Exception"); le.initCause(new SecurityException()); if (debug != null) { debug.println( "original security exception with detail msg " + "replaced by new exception with empty detail msg"); debug.println("original security exception: " + ite.getCause().toString()); } } else { // capture an unexpected LoginModule exception java.io.StringWriter sw = new java.io.StringWriter(); ite.getCause().printStackTrace(new java.io.PrintWriter(sw)); sw.flush(); le = new LoginException(sw.toString()); } if (moduleStack[i].entry.getControlFlag() == AppConfigurationEntry.LoginModuleControlFlag.REQUISITE) { if (debug != null) debug.println(methodName + " REQUISITE failure"); // if REQUISITE, then immediately throw an exception if (methodName.equals(ABORT_METHOD) || methodName.equals(LOGOUT_METHOD)) { if (firstRequiredError == null) firstRequiredError = le; } else { throwException(firstRequiredError, le); } } else if (moduleStack[i].entry.getControlFlag() == AppConfigurationEntry.LoginModuleControlFlag.REQUIRED) { if (debug != null) debug.println(methodName + " REQUIRED failure"); // mark down that a REQUIRED module failed if (firstRequiredError == null) firstRequiredError = le; } else { if (debug != null) debug.println(methodName + " OPTIONAL failure"); // mark down that an OPTIONAL module failed if (firstError == null) firstError = le; } } } // we went thru all the LoginModules. if (firstRequiredError != null) { // a REQUIRED module failed -- return the error throwException(firstRequiredError, null); } else if (success == false && firstError != null) { // no module succeeded -- return the first error throwException(firstError, null); } else if (success == false) { // no module succeeded -- all modules were IGNORED throwException( new LoginException(ResourcesMgr.getString("Login.Failure.all.modules.ignored")), null); } else { // success clearState(); return; } } /** * Wrap the caller-specified CallbackHandler in our own and invoke it within a privileged block, * constrained by the caller's AccessControlContext. */ private static class SecureCallbackHandler implements CallbackHandler { private final java.security.AccessControlContext acc; private final CallbackHandler ch; SecureCallbackHandler(java.security.AccessControlContext acc, CallbackHandler ch) { this.acc = acc; this.ch = ch; } public void handle(final Callback[] callbacks) throws java.io.IOException, UnsupportedCallbackException { try { java.security.AccessController.doPrivileged( new java.security.PrivilegedExceptionAction<Void>() { public Void run() throws java.io.IOException, UnsupportedCallbackException { ch.handle(callbacks); return null; } }, acc); } catch (java.security.PrivilegedActionException pae) { if (pae.getException() instanceof java.io.IOException) { throw (java.io.IOException) pae.getException(); } else { throw (UnsupportedCallbackException) pae.getException(); } } } } /** LoginModule information - incapsulates Configuration info and actual module instances */ private static class ModuleInfo { AppConfigurationEntry entry; Object module; ModuleInfo(AppConfigurationEntry newEntry, Object newModule) { this.entry = newEntry; this.module = newModule; } } }
/* */ public class PKIXCertPathValidator extends CertPathValidatorSpi /* */ { /* 67 */ private static final Debug debug = Debug.getInstance("certpath"); /* */ private Date testDate; /* */ private List<PKIXCertPathChecker> userCheckers; /* */ private String sigProvider; /* */ private BasicChecker basicChecker; /* 72 */ private boolean ocspEnabled = false; /* 73 */ private boolean onlyEECert = false; /* */ /* */ public CertPathValidatorResult engineValidate( CertPath paramCertPath, CertPathParameters paramCertPathParameters) /* */ throws CertPathValidatorException, InvalidAlgorithmParameterException /* */ { /* 98 */ if (debug != null) { /* 99 */ debug.println("PKIXCertPathValidator.engineValidate()..."); /* */ } /* 101 */ if (!(paramCertPathParameters instanceof PKIXParameters)) { /* 102 */ throw new InvalidAlgorithmParameterException( "inappropriate parameters, must be an instance of PKIXParameters"); /* */ } /* */ /* 106 */ if ((!paramCertPath.getType().equals("X.509")) && (!paramCertPath.getType().equals("X509"))) { /* 107 */ throw new InvalidAlgorithmParameterException( "inappropriate certification path type specified, must be X.509 or X509"); /* */ } /* */ /* 111 */ PKIXParameters localPKIXParameters = (PKIXParameters) paramCertPathParameters; /* */ /* 115 */ Set localSet = localPKIXParameters.getTrustAnchors(); /* 116 */ for (Object localObject1 = localSet.iterator(); ((Iterator) localObject1).hasNext(); ) { localObject2 = (TrustAnchor) ((Iterator) localObject1).next(); /* 117 */ if (((TrustAnchor) localObject2).getNameConstraints() != null) { /* 118 */ throw new InvalidAlgorithmParameterException( "name constraints in trust anchor not supported"); /* */ } /* */ /* */ } /* */ /* 133 */ localObject1 = new ArrayList(paramCertPath.getCertificates()); /* */ /* 135 */ if (debug != null) { /* 136 */ if (((ArrayList) localObject1).isEmpty()) { /* 137 */ debug.println("PKIXCertPathValidator.engineValidate() certList is empty"); /* */ } /* */ /* 140 */ debug.println("PKIXCertPathValidator.engineValidate() reversing certpath..."); /* */ } /* */ /* 143 */ Collections.reverse((List) localObject1); /* */ /* 148 */ populateVariables(localPKIXParameters); /* */ /* 152 */ Object localObject2 = null; /* 153 */ if (!((ArrayList) localObject1).isEmpty()) { /* 154 */ localObject2 = (X509Certificate) ((ArrayList) localObject1).get(0); /* */ } /* */ /* 157 */ Object localObject3 = null; /* */ /* 161 */ for (TrustAnchor localTrustAnchor : localSet) { /* 162 */ X509Certificate localX509Certificate = localTrustAnchor.getTrustedCert(); /* 163 */ if (localX509Certificate != null) { /* 164 */ if (debug != null) { /* 165 */ debug.println( "PKIXCertPathValidator.engineValidate() anchor.getTrustedCert() != null"); /* */ } /* */ /* 171 */ if (isWorthTrying(localX509Certificate, (X509Certificate) localObject2)) /* */ { /* 175 */ if (debug != null) /* 176 */ debug.println( "anchor.getTrustedCert().getSubjectX500Principal() = " + localX509Certificate.getSubjectX500Principal()); /* */ } /* */ } /* */ else /* */ { /* 181 */ if (debug != null) { /* 182 */ debug.println( "PKIXCertPathValidator.engineValidate(): anchor.getTrustedCert() == null"); /* */ } /* */ /* */ try /* */ { /* 188 */ PolicyNodeImpl localPolicyNodeImpl = new PolicyNodeImpl( null, "2.5.29.32.0", null, false, Collections.singleton("2.5.29.32.0"), false); /* */ /* 191 */ PolicyNode localPolicyNode = doValidate( localTrustAnchor, paramCertPath, (ArrayList) localObject1, localPKIXParameters, localPolicyNodeImpl); /* */ /* 194 */ return new PKIXCertPathValidatorResult( localTrustAnchor, localPolicyNode, this.basicChecker.getPublicKey()); /* */ } /* */ catch (CertPathValidatorException localCertPathValidatorException) /* */ { /* 198 */ localObject3 = localCertPathValidatorException; /* */ } /* */ } /* */ /* */ } /* */ /* 204 */ if (localObject3 != null) { /* 205 */ throw localObject3; /* */ } /* */ /* 208 */ throw new CertPathValidatorException( "Path does not chain with any of the trust anchors", null, null, -1, PKIXReason.NO_TRUST_ANCHOR); /* */ } /* */ /* */ private boolean isWorthTrying( X509Certificate paramX509Certificate1, X509Certificate paramX509Certificate2) /* */ { /* 220 */ boolean bool = false; /* */ /* 222 */ if (debug != null) { /* 223 */ debug.println( "PKIXCertPathValidator.isWorthTrying() checking if this trusted cert is worth trying ..."); /* */ } /* */ /* 227 */ if (paramX509Certificate2 == null) { /* 228 */ return true; /* */ } /* */ /* 231 */ AdaptableX509CertSelector localAdaptableX509CertSelector = new AdaptableX509CertSelector(); /* */ /* 235 */ localAdaptableX509CertSelector.setSubject( paramX509Certificate2.getIssuerX500Principal()); /* */ /* 238 */ localAdaptableX509CertSelector.setValidityPeriod( paramX509Certificate2.getNotBefore(), paramX509Certificate2.getNotAfter()); /* */ try /* */ { /* 246 */ X509CertImpl localX509CertImpl = X509CertImpl.toImpl(paramX509Certificate2); /* 247 */ localAdaptableX509CertSelector.parseAuthorityKeyIdentifierExtension( localX509CertImpl.getAuthorityKeyIdentifierExtension()); /* */ /* 250 */ bool = localAdaptableX509CertSelector.match(paramX509Certificate1); /* */ } /* */ catch (Exception localException) /* */ { /* */ } /* 255 */ if (debug != null) { /* 256 */ if (bool) /* 257 */ debug.println("YES - try this trustedCert"); /* */ else { /* 259 */ debug.println("NO - don't try this trustedCert"); /* */ } /* */ } /* */ /* 263 */ return bool; /* */ } /* */ /* */ private void populateVariables(PKIXParameters paramPKIXParameters) /* */ { /* 272 */ this.testDate = paramPKIXParameters.getDate(); /* 273 */ if (this.testDate == null) { /* 274 */ this.testDate = new Date(System.currentTimeMillis()); /* */ } /* */ /* 277 */ this.userCheckers = paramPKIXParameters.getCertPathCheckers(); /* 278 */ this.sigProvider = paramPKIXParameters.getSigProvider(); /* */ /* 280 */ if (paramPKIXParameters.isRevocationEnabled()) /* */ { /* 282 */ this.ocspEnabled = ((Boolean) AccessController.doPrivileged( new GetBooleanSecurityPropertyAction("ocsp.enable"))) .booleanValue(); /* */ /* 285 */ this.onlyEECert = ((Boolean) AccessController.doPrivileged( new GetBooleanSecurityPropertyAction( "com.sun.security.onlyCheckRevocationOfEECert"))) .booleanValue(); /* */ } /* */ } /* */ /* */ private PolicyNode doValidate( TrustAnchor paramTrustAnchor, CertPath paramCertPath, ArrayList<X509Certificate> paramArrayList, PKIXParameters paramPKIXParameters, PolicyNodeImpl paramPolicyNodeImpl) /* */ throws CertPathValidatorException /* */ { /* 301 */ int i = paramArrayList.size(); /* */ /* 303 */ this.basicChecker = new BasicChecker(paramTrustAnchor, this.testDate, this.sigProvider, false); /* 304 */ AlgorithmChecker localAlgorithmChecker = new AlgorithmChecker(paramTrustAnchor); /* 305 */ KeyChecker localKeyChecker = new KeyChecker(i, paramPKIXParameters.getTargetCertConstraints()); /* */ /* 307 */ ConstraintsChecker localConstraintsChecker = new ConstraintsChecker(i); /* */ /* 310 */ PolicyChecker localPolicyChecker = new PolicyChecker( paramPKIXParameters.getInitialPolicies(), i, paramPKIXParameters.isExplicitPolicyRequired(), paramPKIXParameters.isPolicyMappingInhibited(), paramPKIXParameters.isAnyPolicyInhibited(), paramPKIXParameters.getPolicyQualifiersRejected(), paramPolicyNodeImpl); /* */ /* 317 */ UntrustedChecker localUntrustedChecker = new UntrustedChecker(); /* */ /* 319 */ ArrayList localArrayList = new ArrayList(); /* */ /* 322 */ localArrayList.add(localUntrustedChecker); /* 323 */ localArrayList.add(localAlgorithmChecker); /* 324 */ localArrayList.add(localKeyChecker); /* 325 */ localArrayList.add(localConstraintsChecker); /* 326 */ localArrayList.add(localPolicyChecker); /* 327 */ localArrayList.add(this.basicChecker); /* */ /* 330 */ if (paramPKIXParameters.isRevocationEnabled()) /* */ { /* 333 */ if (this.ocspEnabled) { /* 334 */ localObject = new OCSPChecker(paramCertPath, paramPKIXParameters, this.onlyEECert); /* */ /* 336 */ localArrayList.add(localObject); /* */ } /* */ /* 340 */ localObject = new CrlRevocationChecker( paramTrustAnchor, paramPKIXParameters, paramArrayList, this.onlyEECert); /* */ /* 342 */ localArrayList.add(localObject); /* */ } /* */ /* 346 */ localArrayList.addAll(this.userCheckers); /* */ /* 348 */ Object localObject = new PKIXMasterCertPathValidator(localArrayList); /* */ /* 351 */ ((PKIXMasterCertPathValidator) localObject).validate(paramCertPath, paramArrayList); /* */ /* 353 */ return localPolicyChecker.getPolicyTree(); /* */ } /* */ }
/* */ public CertPathValidatorResult engineValidate( CertPath paramCertPath, CertPathParameters paramCertPathParameters) /* */ throws CertPathValidatorException, InvalidAlgorithmParameterException /* */ { /* 98 */ if (debug != null) { /* 99 */ debug.println("PKIXCertPathValidator.engineValidate()..."); /* */ } /* 101 */ if (!(paramCertPathParameters instanceof PKIXParameters)) { /* 102 */ throw new InvalidAlgorithmParameterException( "inappropriate parameters, must be an instance of PKIXParameters"); /* */ } /* */ /* 106 */ if ((!paramCertPath.getType().equals("X.509")) && (!paramCertPath.getType().equals("X509"))) { /* 107 */ throw new InvalidAlgorithmParameterException( "inappropriate certification path type specified, must be X.509 or X509"); /* */ } /* */ /* 111 */ PKIXParameters localPKIXParameters = (PKIXParameters) paramCertPathParameters; /* */ /* 115 */ Set localSet = localPKIXParameters.getTrustAnchors(); /* 116 */ for (Object localObject1 = localSet.iterator(); ((Iterator) localObject1).hasNext(); ) { localObject2 = (TrustAnchor) ((Iterator) localObject1).next(); /* 117 */ if (((TrustAnchor) localObject2).getNameConstraints() != null) { /* 118 */ throw new InvalidAlgorithmParameterException( "name constraints in trust anchor not supported"); /* */ } /* */ /* */ } /* */ /* 133 */ localObject1 = new ArrayList(paramCertPath.getCertificates()); /* */ /* 135 */ if (debug != null) { /* 136 */ if (((ArrayList) localObject1).isEmpty()) { /* 137 */ debug.println("PKIXCertPathValidator.engineValidate() certList is empty"); /* */ } /* */ /* 140 */ debug.println("PKIXCertPathValidator.engineValidate() reversing certpath..."); /* */ } /* */ /* 143 */ Collections.reverse((List) localObject1); /* */ /* 148 */ populateVariables(localPKIXParameters); /* */ /* 152 */ Object localObject2 = null; /* 153 */ if (!((ArrayList) localObject1).isEmpty()) { /* 154 */ localObject2 = (X509Certificate) ((ArrayList) localObject1).get(0); /* */ } /* */ /* 157 */ Object localObject3 = null; /* */ /* 161 */ for (TrustAnchor localTrustAnchor : localSet) { /* 162 */ X509Certificate localX509Certificate = localTrustAnchor.getTrustedCert(); /* 163 */ if (localX509Certificate != null) { /* 164 */ if (debug != null) { /* 165 */ debug.println( "PKIXCertPathValidator.engineValidate() anchor.getTrustedCert() != null"); /* */ } /* */ /* 171 */ if (isWorthTrying(localX509Certificate, (X509Certificate) localObject2)) /* */ { /* 175 */ if (debug != null) /* 176 */ debug.println( "anchor.getTrustedCert().getSubjectX500Principal() = " + localX509Certificate.getSubjectX500Principal()); /* */ } /* */ } /* */ else /* */ { /* 181 */ if (debug != null) { /* 182 */ debug.println( "PKIXCertPathValidator.engineValidate(): anchor.getTrustedCert() == null"); /* */ } /* */ /* */ try /* */ { /* 188 */ PolicyNodeImpl localPolicyNodeImpl = new PolicyNodeImpl( null, "2.5.29.32.0", null, false, Collections.singleton("2.5.29.32.0"), false); /* */ /* 191 */ PolicyNode localPolicyNode = doValidate( localTrustAnchor, paramCertPath, (ArrayList) localObject1, localPKIXParameters, localPolicyNodeImpl); /* */ /* 194 */ return new PKIXCertPathValidatorResult( localTrustAnchor, localPolicyNode, this.basicChecker.getPublicKey()); /* */ } /* */ catch (CertPathValidatorException localCertPathValidatorException) /* */ { /* 198 */ localObject3 = localCertPathValidatorException; /* */ } /* */ } /* */ /* */ } /* */ /* 204 */ if (localObject3 != null) { /* 205 */ throw localObject3; /* */ } /* */ /* 208 */ throw new CertPathValidatorException( "Path does not chain with any of the trust anchors", null, null, -1, PKIXReason.NO_TRUST_ANCHOR); /* */ }
private static void initialize() { props = new Properties(); boolean loadedProps = false; boolean overrideAll = false; // first load the system properties file // to determine the value of security.overridePropertiesFile File propFile = securityPropFile("java.security"); if (propFile.exists()) { try { FileInputStream fis = new FileInputStream(propFile); InputStream is = new BufferedInputStream(fis); props.load(is); is.close(); loadedProps = true; if (sdebug != null) { sdebug.println("reading security properties file: " + propFile); } } catch (IOException e) { if (sdebug != null) { sdebug.println("unable to load security properties from " + propFile); e.printStackTrace(); } } } if ("true".equalsIgnoreCase(props.getProperty("security.overridePropertiesFile"))) { String extraPropFile = System.getProperty("java.security.properties"); if (extraPropFile != null && extraPropFile.startsWith("=")) { overrideAll = true; extraPropFile = extraPropFile.substring(1); } if (overrideAll) { props = new Properties(); if (sdebug != null) { sdebug.println("overriding other security properties files!"); } } // now load the user-specified file so its values // will win if they conflict with the earlier values if (extraPropFile != null) { try { URL propURL; extraPropFile = PropertyExpander.expand(extraPropFile); propFile = new File(extraPropFile); if (propFile.exists()) { propURL = new URL("file:" + propFile.getCanonicalPath()); } else { propURL = new URL(extraPropFile); } BufferedInputStream bis = new BufferedInputStream(propURL.openStream()); props.load(bis); bis.close(); loadedProps = true; if (sdebug != null) { sdebug.println("reading security properties file: " + propURL); if (overrideAll) { sdebug.println("overriding other security properties files!"); } } } catch (Exception e) { if (sdebug != null) { sdebug.println("unable to load security properties from " + extraPropFile); e.printStackTrace(); } } } } if (!loadedProps) { initializeStatic(); if (sdebug != null) { sdebug.println("unable to load security properties " + "-- using defaults"); } } }
/* */ Permission resolve(Permission paramPermission, Certificate[] paramArrayOfCertificate) /* */ { /* 230 */ if (this.certs != null) /* */ { /* 232 */ if (paramArrayOfCertificate == null) { /* 233 */ return null; /* */ } /* */ /* 238 */ for (int j = 0; j < this.certs.length; j++) { /* 239 */ int i = 0; /* 240 */ for (int k = 0; k < paramArrayOfCertificate.length; k++) { /* 241 */ if (this.certs[j].equals(paramArrayOfCertificate[k])) { /* 242 */ i = 1; /* 243 */ break; /* */ } /* */ } /* 246 */ if (i == 0) return null; /* */ } /* */ } /* */ try /* */ { /* 250 */ Class localClass = paramPermission.getClass(); /* */ /* 252 */ if ((this.name == null) && (this.actions == null)) { /* */ try { /* 254 */ Constructor localConstructor1 = localClass.getConstructor(PARAMS0); /* 255 */ return (Permission) localConstructor1.newInstance(new Object[0]); /* */ } catch (NoSuchMethodException localNoSuchMethodException2) { /* */ try { /* 258 */ Constructor localConstructor4 = localClass.getConstructor(PARAMS1); /* 259 */ return (Permission) localConstructor4.newInstance(new Object[] {this.name}); /* */ } /* */ catch (NoSuchMethodException localNoSuchMethodException4) { /* 262 */ Constructor localConstructor6 = localClass.getConstructor(PARAMS2); /* 263 */ return (Permission) localConstructor6.newInstance(new Object[] {this.name, this.actions}); /* */ } /* */ } /* */ } /* */ /* 268 */ if ((this.name != null) && (this.actions == null)) { /* */ try { /* 270 */ Constructor localConstructor2 = localClass.getConstructor(PARAMS1); /* 271 */ return (Permission) localConstructor2.newInstance(new Object[] {this.name}); /* */ } /* */ catch (NoSuchMethodException localNoSuchMethodException3) { /* 274 */ Constructor localConstructor5 = localClass.getConstructor(PARAMS2); /* 275 */ return (Permission) localConstructor5.newInstance(new Object[] {this.name, this.actions}); /* */ } /* */ } /* */ /* 279 */ Constructor localConstructor3 = localClass.getConstructor(PARAMS2); /* 280 */ return (Permission) localConstructor3.newInstance(new Object[] {this.name, this.actions}); /* */ } /* */ catch (NoSuchMethodException localNoSuchMethodException1) /* */ { /* 285 */ if (debug != null) { /* 286 */ debug.println( "NoSuchMethodException:\n could not find proper constructor for " + this.type); /* */ /* 288 */ localNoSuchMethodException1.printStackTrace(); /* */ } /* 290 */ return null; /* */ } catch (Exception localException) { /* 292 */ if (debug != null) { /* 293 */ debug.println("unable to instantiate " + this.name); /* 294 */ localException.printStackTrace(); /* */ } /* */ } /* 296 */ return null; /* */ }
/* */ public final class UnresolvedPermission extends Permission /* */ implements Serializable /* */ { /* */ private static final long serialVersionUID = -4821973115467008846L; /* 109 */ private static final Debug debug = Debug.getInstance("policy,access", "UnresolvedPermission"); /* */ private String type; /* */ private String name; /* */ private String actions; /* */ private transient Certificate[] certs; /* 221 */ private static final Class[] PARAMS0 = new Class[0]; /* 222 */ private static final Class[] PARAMS1 = {String.class}; /* 223 */ private static final Class[] PARAMS2 = {String.class, String.class}; /* */ /* */ public UnresolvedPermission( String paramString1, String paramString2, String paramString3, Certificate[] paramArrayOfCertificate) /* */ { /* 159 */ super(paramString1); /* */ /* 161 */ if (paramString1 == null) { /* 162 */ throw new NullPointerException("type can't be null"); /* */ } /* 164 */ this.type = paramString1; /* 165 */ this.name = paramString2; /* 166 */ this.actions = paramString3; /* 167 */ if (paramArrayOfCertificate != null) /* */ { /* 169 */ for (int i = 0; i < paramArrayOfCertificate.length; i++) { /* 170 */ if (!(paramArrayOfCertificate[i] instanceof X509Certificate)) /* */ { /* 173 */ this.certs = ((Certificate[]) paramArrayOfCertificate.clone()); /* 174 */ break; /* */ } /* */ } /* */ /* 178 */ if (this.certs == null) /* */ { /* 181 */ i = 0; /* 182 */ int j = 0; /* 183 */ while (i < paramArrayOfCertificate.length) { /* 184 */ j++; /* 185 */ while ((i + 1 < paramArrayOfCertificate.length) && (((X509Certificate) paramArrayOfCertificate[i]) .getIssuerDN() .equals(((X509Certificate) paramArrayOfCertificate[(i + 1)]).getSubjectDN()))) /* */ { /* 188 */ i++; /* */ } /* 190 */ i++; /* */ } /* 192 */ if (j == paramArrayOfCertificate.length) /* */ { /* 195 */ this.certs = ((Certificate[]) paramArrayOfCertificate.clone()); /* */ } /* */ /* 198 */ if (this.certs == null) /* */ { /* 200 */ ArrayList localArrayList = new ArrayList(); /* */ /* 202 */ i = 0; /* 203 */ while (i < paramArrayOfCertificate.length) { /* 204 */ localArrayList.add(paramArrayOfCertificate[i]); /* 205 */ while ((i + 1 < paramArrayOfCertificate.length) && (((X509Certificate) paramArrayOfCertificate[i]) .getIssuerDN() .equals(((X509Certificate) paramArrayOfCertificate[(i + 1)]).getSubjectDN()))) /* */ { /* 208 */ i++; /* */ } /* 210 */ i++; /* */ } /* 212 */ this.certs = new Certificate[localArrayList.size()]; /* */ /* 214 */ localArrayList.toArray(this.certs); /* */ } /* */ } /* */ } /* */ } /* */ /* */ Permission resolve(Permission paramPermission, Certificate[] paramArrayOfCertificate) /* */ { /* 230 */ if (this.certs != null) /* */ { /* 232 */ if (paramArrayOfCertificate == null) { /* 233 */ return null; /* */ } /* */ /* 238 */ for (int j = 0; j < this.certs.length; j++) { /* 239 */ int i = 0; /* 240 */ for (int k = 0; k < paramArrayOfCertificate.length; k++) { /* 241 */ if (this.certs[j].equals(paramArrayOfCertificate[k])) { /* 242 */ i = 1; /* 243 */ break; /* */ } /* */ } /* 246 */ if (i == 0) return null; /* */ } /* */ } /* */ try /* */ { /* 250 */ Class localClass = paramPermission.getClass(); /* */ /* 252 */ if ((this.name == null) && (this.actions == null)) { /* */ try { /* 254 */ Constructor localConstructor1 = localClass.getConstructor(PARAMS0); /* 255 */ return (Permission) localConstructor1.newInstance(new Object[0]); /* */ } catch (NoSuchMethodException localNoSuchMethodException2) { /* */ try { /* 258 */ Constructor localConstructor4 = localClass.getConstructor(PARAMS1); /* 259 */ return (Permission) localConstructor4.newInstance(new Object[] {this.name}); /* */ } /* */ catch (NoSuchMethodException localNoSuchMethodException4) { /* 262 */ Constructor localConstructor6 = localClass.getConstructor(PARAMS2); /* 263 */ return (Permission) localConstructor6.newInstance(new Object[] {this.name, this.actions}); /* */ } /* */ } /* */ } /* */ /* 268 */ if ((this.name != null) && (this.actions == null)) { /* */ try { /* 270 */ Constructor localConstructor2 = localClass.getConstructor(PARAMS1); /* 271 */ return (Permission) localConstructor2.newInstance(new Object[] {this.name}); /* */ } /* */ catch (NoSuchMethodException localNoSuchMethodException3) { /* 274 */ Constructor localConstructor5 = localClass.getConstructor(PARAMS2); /* 275 */ return (Permission) localConstructor5.newInstance(new Object[] {this.name, this.actions}); /* */ } /* */ } /* */ /* 279 */ Constructor localConstructor3 = localClass.getConstructor(PARAMS2); /* 280 */ return (Permission) localConstructor3.newInstance(new Object[] {this.name, this.actions}); /* */ } /* */ catch (NoSuchMethodException localNoSuchMethodException1) /* */ { /* 285 */ if (debug != null) { /* 286 */ debug.println( "NoSuchMethodException:\n could not find proper constructor for " + this.type); /* */ /* 288 */ localNoSuchMethodException1.printStackTrace(); /* */ } /* 290 */ return null; /* */ } catch (Exception localException) { /* 292 */ if (debug != null) { /* 293 */ debug.println("unable to instantiate " + this.name); /* 294 */ localException.printStackTrace(); /* */ } /* */ } /* 296 */ return null; /* */ } /* */ /* */ public boolean implies(Permission paramPermission) /* */ { /* 310 */ return false; /* */ } /* */ /* */ public boolean equals(Object paramObject) /* */ { /* 330 */ if (paramObject == this) { /* 331 */ return true; /* */ } /* 333 */ if (!(paramObject instanceof UnresolvedPermission)) /* 334 */ return false; /* 335 */ UnresolvedPermission localUnresolvedPermission = (UnresolvedPermission) paramObject; /* */ /* 338 */ if (!this.type.equals(localUnresolvedPermission.type)) { /* 339 */ return false; /* */ } /* */ /* 343 */ if (this.name == null) { /* 344 */ if (localUnresolvedPermission.name != null) /* 345 */ return false; /* */ } /* 347 */ else if (!this.name.equals(localUnresolvedPermission.name)) { /* 348 */ return false; /* */ } /* */ /* 352 */ if (this.actions == null) { /* 353 */ if (localUnresolvedPermission.actions != null) { /* 354 */ return false; /* */ } /* */ } /* 357 */ else if (!this.actions.equals(localUnresolvedPermission.actions)) { /* 358 */ return false; /* */ } /* */ /* 363 */ if (((this.certs == null) && (localUnresolvedPermission.certs != null)) || ((this.certs != null) && (localUnresolvedPermission.certs == null)) || ((this.certs != null) && (localUnresolvedPermission.certs != null) && (this.certs.length != localUnresolvedPermission.certs.length))) /* */ { /* 367 */ return false; /* */ } /* */ int k; /* */ int j; /* 373 */ for (int i = 0; (this.certs != null) && (i < this.certs.length); i++) { /* 374 */ k = 0; /* 375 */ for (j = 0; j < localUnresolvedPermission.certs.length; j++) { /* 376 */ if (this.certs[i].equals(localUnresolvedPermission.certs[j])) { /* 377 */ k = 1; /* 378 */ break; /* */ } /* */ } /* 381 */ if (k == 0) return false; /* */ } /* */ /* 384 */ for (i = 0; (localUnresolvedPermission.certs != null) && (i < localUnresolvedPermission.certs.length); i++) { /* 385 */ k = 0; /* 386 */ for (j = 0; j < this.certs.length; j++) { /* 387 */ if (localUnresolvedPermission.certs[i].equals(this.certs[j])) { /* 388 */ k = 1; /* 389 */ break; /* */ } /* */ } /* 392 */ if (k == 0) return false; /* */ } /* 394 */ return true; /* */ } /* */ /* */ public int hashCode() /* */ { /* 404 */ int i = this.type.hashCode(); /* 405 */ if (this.name != null) /* 406 */ i ^= this.name.hashCode(); /* 407 */ if (this.actions != null) /* 408 */ i ^= this.actions.hashCode(); /* 409 */ return i; /* */ } /* */ /* */ public String getActions() /* */ { /* 424 */ return ""; /* */ } /* */ /* */ public String getUnresolvedType() /* */ { /* 437 */ return this.type; /* */ } /* */ /* */ public String getUnresolvedName() /* */ { /* 451 */ return this.name; /* */ } /* */ /* */ public String getUnresolvedActions() /* */ { /* 465 */ return this.actions; /* */ } /* */ /* */ public Certificate[] getUnresolvedCerts() /* */ { /* 479 */ return this.certs == null ? null : (Certificate[]) this.certs.clone(); /* */ } /* */ /* */ public String toString() /* */ { /* 490 */ return "(unresolved " + this.type + " " + this.name + " " + this.actions + ")"; /* */ } /* */ /* */ public PermissionCollection newPermissionCollection() /* */ { /* 502 */ return new UnresolvedPermissionCollection(); /* */ } /* */ /* */ private void writeObject(ObjectOutputStream paramObjectOutputStream) /* */ throws IOException /* */ { /* 524 */ paramObjectOutputStream.defaultWriteObject(); /* */ /* 526 */ if ((this.certs == null) || (this.certs.length == 0)) { /* 527 */ paramObjectOutputStream.writeInt(0); /* */ } /* */ else { /* 530 */ paramObjectOutputStream.writeInt(this.certs.length); /* */ /* 532 */ for (int i = 0; i < this.certs.length; i++) { /* 533 */ Certificate localCertificate = this.certs[i]; /* */ try { /* 535 */ paramObjectOutputStream.writeUTF(localCertificate.getType()); /* 536 */ byte[] arrayOfByte = localCertificate.getEncoded(); /* 537 */ paramObjectOutputStream.writeInt(arrayOfByte.length); /* 538 */ paramObjectOutputStream.write(arrayOfByte); /* */ } catch (CertificateEncodingException localCertificateEncodingException) { /* 540 */ throw new IOException(localCertificateEncodingException.getMessage()); /* */ } /* */ } /* */ } /* */ } /* */ /* */ private void readObject(ObjectInputStream paramObjectInputStream) /* */ throws IOException, ClassNotFoundException /* */ { /* 553 */ Hashtable localHashtable = null; /* */ /* 555 */ paramObjectInputStream.defaultReadObject(); /* */ /* 557 */ if (this.type == null) { /* 558 */ throw new NullPointerException("type can't be null"); /* */ } /* */ /* 561 */ int i = paramObjectInputStream.readInt(); /* 562 */ if (i > 0) /* */ { /* 565 */ localHashtable = new Hashtable(3); /* 566 */ this.certs = new Certificate[i]; /* */ } /* */ /* 569 */ for (int j = 0; j < i; j++) /* */ { /* 572 */ String str = paramObjectInputStream.readUTF(); /* */ CertificateFactory localCertificateFactory; /* 573 */ if (localHashtable.containsKey(str)) /* */ { /* 575 */ localCertificateFactory = (CertificateFactory) localHashtable.get(str); /* */ } /* */ else { /* */ try { /* 579 */ localCertificateFactory = CertificateFactory.getInstance(str); /* */ } catch (CertificateException localCertificateException1) { /* 581 */ throw new ClassNotFoundException( "Certificate factory for " + str + " not found"); /* */ } /* */ /* 585 */ localHashtable.put(str, localCertificateFactory); /* */ } /* */ /* 588 */ byte[] arrayOfByte = null; /* */ try { /* 590 */ arrayOfByte = new byte[paramObjectInputStream.readInt()]; /* */ } catch (OutOfMemoryError localOutOfMemoryError) { /* 592 */ throw new IOException("Certificate too big"); /* */ } /* 594 */ paramObjectInputStream.readFully(arrayOfByte); /* 595 */ ByteArrayInputStream localByteArrayInputStream = new ByteArrayInputStream(arrayOfByte); /* */ try { /* 597 */ this.certs[j] = localCertificateFactory.generateCertificate(localByteArrayInputStream); /* */ } catch (CertificateException localCertificateException2) { /* 599 */ throw new IOException(localCertificateException2.getMessage()); /* */ } /* 601 */ localByteArrayInputStream.close(); /* */ } /* */ } /* */ }
/** * This class represents a reverse builder, which is able to retrieve matching certificates from * CertStores and verify a particular certificate against a ReverseState. * * @version 1.13 01/23/03 * @since 1.4 * @author Sean Mullan * @author Yassir Elley */ class ReverseBuilder extends Builder { private Debug debug = Debug.getInstance("certpath"); private Date date; private X509CertSelector targetCertSelector; Set initPolicies; /** * Initialize the builder with the input parameters. * * @param params the parameter set used to build a certification path */ ReverseBuilder(PKIXBuilderParameters buildParams, X500Principal targetSubjectDN) { super(buildParams, targetSubjectDN); // Initialize date if not specified date = buildParams.getDate(); if (date == null) { date = new Date(); } targetCertSelector = (X509CertSelector) buildParams.getTargetCertConstraints(); Set initialPolicies = buildParams.getInitialPolicies(); initPolicies = new HashSet(); if (initialPolicies.isEmpty()) { // if no initialPolicies are specified by user, set // initPolicies to be anyPolicy by default initPolicies.add(PolicyChecker.ANY_POLICY); } else { Iterator i = initialPolicies.iterator(); while (i.hasNext()) { initPolicies.add(i.next()); } } } /** * Retrieves all certs from a CertStore which satisfy the requirements specified in the parameters * and the current PKIX state (name constraints, policy constraints, etc). * * @param currentState the current state. Must be an instance of <code>ReverseState</code> */ Collection getMatchingCerts(State currState) throws CertStoreException, CertificateException, IOException { ReverseState currentState = (ReverseState) currState; if (debug != null) debug.println("In ReverseBuilder.getMatchingCerts."); /* * The last certificate could be an EE or a CA certificate * (we may be building a partial certification path or * establishing trust in a CA). * * Try the EE certs before the CA certs. It will be more * common to build a path to an end entity. */ Collection certs = getMatchingEECerts(currentState); certs.addAll(getMatchingCACerts(currentState)); return certs; } /* * Retrieves all end-entity certificates which satisfy constraints * and requirements specified in the parameters and PKIX state. */ private Collection getMatchingEECerts(ReverseState currentState) throws CertStoreException, CertificateException, IOException { /* * Compose a CertSelector to filter out * certs which do not satisfy requirements. * * First, retrieve clone of current target cert constraints, * and then add more selection criteria based on current validation state. */ X509CertSelector sel = (X509CertSelector) buildParams.getTargetCertConstraints(); /* * Match on issuer (subject of previous cert) */ CertPathHelper.setIssuer(sel, currentState.subjectDN); /* * Match on certificate validity date. */ sel.setCertificateValid(date); /* * Policy processing optimizations */ if (currentState.explicitPolicy == 0) sel.setPolicy(getMatchingPolicies()); /* * If previous cert has a subject key identifier extension, * use it to match on authority key identifier extension. */ /*if (currentState.subjKeyId != null) { AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension( (KeyIdentifier) currentState.subjKeyId.get(SubjectKeyIdentifierExtension.KEY_ID), null, null); sel.setAuthorityKeyIdentifier(authKeyId.getExtensionValue()); }*/ /* * Require EE certs */ sel.setBasicConstraints(-2); /* Retrieve matching certs from CertStores */ HashSet eeCerts = new HashSet(); addMatchingCerts(sel, buildParams.getCertStores(), eeCerts); if (debug != null) { debug.println("ReverseBuilder.getMatchingEECerts got " + eeCerts.size() + " certs."); } return eeCerts; } /* * Retrieves all CA certificates which satisfy constraints * and requirements specified in the parameters and PKIX state. */ private Collection getMatchingCACerts(ReverseState currentState) throws CertificateException, CertStoreException, IOException { /* * Compose a CertSelector to filter out * certs which do not satisfy requirements. */ X509CertSelector sel = new X509CertSelector(); /* * Match on issuer (subject of previous cert) */ CertPathHelper.setIssuer(sel, currentState.subjectDN); /* * Match on certificate validity date. */ sel.setCertificateValid(date); /* * Match on target subject name (checks that current cert's * name constraints permit it to certify target). * (4 is the integer type for DIRECTORY name). */ sel.addPathToName(4, targetCertSelector.getSubjectAsBytes()); /* * Policy processing optimizations */ if (currentState.explicitPolicy == 0) sel.setPolicy(getMatchingPolicies()); /* * If previous cert has a subject key identifier extension, * use it to match on authority key identifier extension. */ /*if (currentState.subjKeyId != null) { AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension( (KeyIdentifier) currentState.subjKeyId.get(SubjectKeyIdentifierExtension.KEY_ID), null, null); sel.setAuthorityKeyIdentifier(authKeyId.getExtensionValue()); }*/ /* * Require CA certs */ sel.setBasicConstraints(0); /* Retrieve matching certs from CertStores */ ArrayList reverseCerts = new ArrayList(); addMatchingCerts(sel, buildParams.getCertStores(), reverseCerts); /* Sort remaining certs using name constraints */ Collections.sort(reverseCerts, new PKIXCertComparator()); if (debug != null) debug.println("ReverseBuilder.getMatchingCACerts got " + reverseCerts.size() + " certs."); return reverseCerts; } /* * This inner class compares 2 PKIX certificates according to which * should be tried first when building a path to the target. For * now, the algorithm is to look at name constraints in each cert and those * which constrain the path closer to the target should be * ranked higher. Later, we may want to consider other components, * such as key identifiers. */ class PKIXCertComparator implements Comparator { private Debug debug = Debug.getInstance("certpath"); public int compare(Object o1, Object o2) { X509Certificate cert1 = (X509Certificate) o1; X509Certificate cert2 = (X509Certificate) o2; /* * if either cert certifies the target, always * put at head of list. */ if (cert1.getSubjectX500Principal().equals(targetSubjectDN)) { return -1; } if (cert2.getSubjectX500Principal().equals(targetSubjectDN)) { return 1; } int targetDist1; int targetDist2; try { X500Name targetSubjectName = X500Name.asX500Name(targetSubjectDN); targetDist1 = Builder.targetDistance(null, cert1, targetSubjectName); targetDist2 = Builder.targetDistance(null, cert2, targetSubjectName); } catch (IOException e) { if (debug != null) { debug.println("IOException in call to Builder.targetDistance"); e.printStackTrace(); } throw new ClassCastException("Invalid target subject distinguished name"); } if (targetDist1 == targetDist2) return 0; if (targetDist1 == -1) return 1; if (targetDist1 < targetDist2) return -1; return 1; } } /** * Verifies a matching certificate. * * <p>This method executes any of the validation steps in the PKIX path validation algorithm which * were not satisfied via filtering out non-compliant certificates with certificate matching * rules. * * <p>If the last certificate is being verified (the one whose subject matches the target subject, * then the steps in Section 6.1.4 of the Certification Path Validation algorithm are NOT * executed, regardless of whether or not the last cert is an end-entity cert or not. This allows * callers to certify CA certs as well as EE certs. * * @param cert the certificate to be verified * @param currentState the current state against which the cert is verified * @param certPathList the certPathList generated thus far */ void verifyCert(X509Certificate cert, State currState, List certPathList) throws GeneralSecurityException { if (debug != null) debug.println( "ReverseBuilder.verifyCert(SN: " + Debug.toHexString(cert.getSerialNumber()) + "\n Subject: " + cert.getSubjectX500Principal() + ")"); ReverseState currentState = (ReverseState) currState; /* we don't perform any validation of the trusted cert */ if (currentState.isInitial()) { return; } /* * check for looping - abort a loop if * ((we encounter the same certificate twice) AND * ((policyMappingInhibited = true) OR (no policy mapping * extensions can be found between the occurences of the same * certificate))) * in order to facilitate the check to see if there are * any policy mapping extensions found between the occurences * of the same certificate, we reverse the certpathlist first */ if ((certPathList != null) && (!certPathList.isEmpty())) { List reverseCertList = new ArrayList(); Iterator iter = certPathList.iterator(); while (iter.hasNext()) { reverseCertList.add(0, iter.next()); } Iterator cpListIter = reverseCertList.iterator(); boolean policyMappingFound = false; while (cpListIter.hasNext()) { X509Certificate cpListCert = (X509Certificate) cpListIter.next(); X509CertImpl cpListCertImpl = X509CertImpl.toImpl(cpListCert); PolicyMappingsExtension policyMappingsExt = cpListCertImpl.getPolicyMappingsExtension(); if (policyMappingsExt != null) { policyMappingFound = true; } if (debug != null) debug.println("policyMappingFound = " + policyMappingFound); if (cert.equals(cpListCert)) { if ((buildParams.isPolicyMappingInhibited()) || (!policyMappingFound)) { if (debug != null) debug.println("loop detected!!"); throw new CertPathValidatorException("loop detected"); } } } } /* check if target cert */ boolean finalCert = cert.getSubjectX500Principal().equals(targetSubjectDN); /* check if CA cert */ boolean caCert = (cert.getBasicConstraints() != -1 ? true : false); /* if there are more certs to follow, verify certain constraints */ if (!finalCert) { /* check if CA cert */ if (!caCert) throw new CertPathValidatorException("cert is NOT a CA cert"); /* If the certificate was not self-issued, verify that * remainingCerts is greater than zero */ if ((currentState.remainingCACerts <= 0) && !X509CertImpl.isSelfIssued(cert)) { throw new CertPathValidatorException("pathLenConstraint violated, path too long"); } /* * Check keyUsage extension (only if CA cert and not final cert) */ KeyChecker.verifyCAKeyUsage(cert); } else { /* * If final cert, check that it satisfies specified target * constraints */ if (targetCertSelector.match(cert) == false) { throw new CertPathValidatorException("target certificate " + "constraints check failed"); } } /* * Check revocation. */ if (buildParams.isRevocationEnabled()) { boolean crlSign = currentState.crlChecker.check(cert, currentState.pubKey, true); // if this cert can't vouch for the CRL on the next cert, and // if this wasn't the last cert in the chain, then we can't // keep going from here! // NOTE: if we ever add indirect/idp support, this will have // to change... if ((!crlSign) && (!finalCert)) throw new CertPathValidatorException("cert can't vouch for crl"); } /* Check name constraints if this is not a self-issued cert */ if (finalCert || !X509CertImpl.isSelfIssued(cert)) { if (currentState.nc != null) { try { if (!currentState.nc.verify(cert)) { throw new CertPathValidatorException("name constraints check failed"); } } catch (IOException ioe) { throw new CertPathValidatorException(ioe); } } } /* * Check policy */ X509CertImpl certImpl = X509CertImpl.toImpl(cert); currentState.rootNode = PolicyChecker.processPolicies( currentState.certIndex, initPolicies, currentState.explicitPolicy, currentState.policyMapping, currentState.inhibitAnyPolicy, buildParams.getPolicyQualifiersRejected(), currentState.rootNode, certImpl, finalCert); /* * Check CRITICAL private extensions */ Set unresolvedCritExts = cert.getCriticalExtensionOIDs(); if (unresolvedCritExts == null) { unresolvedCritExts = Collections.EMPTY_SET; } Iterator i = currentState.userCheckers.iterator(); while (i.hasNext()) { PKIXCertPathChecker checker = (PKIXCertPathChecker) i.next(); checker.check(cert, unresolvedCritExts); } /* * Look at the remaining extensions and remove any ones we have * already checked. If there are any left, throw an exception! */ if (!unresolvedCritExts.isEmpty()) { unresolvedCritExts.remove(PKIXExtensions.BasicConstraints_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.NameConstraints_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.CertificatePolicies_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.PolicyMappings_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.PolicyConstraints_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.InhibitAnyPolicy_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.SubjectAlternativeName_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.KeyUsage_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.ExtendedKeyUsage_Id.toString()); if (!unresolvedCritExts.isEmpty()) throw new CertificateException("Unrecognized critical extension(s)"); } /* * Check signature. */ if (buildParams.getSigProvider() != null) { cert.verify(currentState.pubKey, buildParams.getSigProvider()); } else { cert.verify(currentState.pubKey); } } /** * Verifies whether the input certificate completes the path. This checks whether the cert is the * target certificate. * * @param cert the certificate to test * @return a boolean value indicating whether the cert completes the path. */ boolean isPathCompleted(X509Certificate cert) { return cert.getSubjectX500Principal().equals(targetSubjectDN); } /** * Adds the certificate to the certPathList * * @param cert the certificate to be added * @param certPathList the certification path list */ void addCertToPath(X509Certificate cert, LinkedList certPathList) { certPathList.addLast(cert); } /** * Removes final certificate from the certPathList * * @param certPathList the certification path list */ void removeFinalCertFromPath(LinkedList certPathList) { certPathList.removeLast(); } }
/* * This method performs a depth first search for a certification * path while building forward which meets the requirements set in * the parameters object. * It uses an adjacency list to store all certificates which were * tried (i.e. at one time added to the path - they may not end up in * the final path if backtracking occurs). This information can * be used later to debug or demo the build. * * See "Data Structure and Algorithms, by Aho, Hopcroft, and Ullman" * for an explanation of the DFS algorithm. * * @param dN the distinguished name being currently searched for certs * @param currentState the current PKIX validation state */ private void depthFirstSearchForward( X500Principal dN, ForwardState currentState, ForwardBuilder builder, List<List<Vertex>> adjList, LinkedList<X509Certificate> cpList) throws GeneralSecurityException, IOException { if (debug != null) { debug.println( "SunCertPathBuilder.depthFirstSearchForward(" + dN + ", " + currentState.toString() + ")"); } /* * Find all the certificates issued to dN which * satisfy the PKIX certification path constraints. */ Collection<X509Certificate> certs = builder.getMatchingCerts(currentState, buildParams.certStores()); List<Vertex> vertices = addVertices(certs, adjList); if (debug != null) { debug.println( "SunCertPathBuilder.depthFirstSearchForward(): " + "certs.size=" + vertices.size()); } /* * For each cert in the collection, verify anything * that hasn't been checked yet (signature, revocation, etc) * and check for loops. Call depthFirstSearchForward() * recursively for each good cert. */ vertices: for (Vertex vertex : vertices) { /** * Restore state to currentState each time through the loop. This is important because some of * the user-defined checkers modify the state, which MUST be restored if the cert eventually * fails to lead to the target and the next matching cert is tried. */ ForwardState nextState = (ForwardState) currentState.clone(); X509Certificate cert = vertex.getCertificate(); try { builder.verifyCert(cert, nextState, cpList); } catch (GeneralSecurityException gse) { if (debug != null) { debug.println( "SunCertPathBuilder.depthFirstSearchForward()" + ": validation failed: " + gse); gse.printStackTrace(); } vertex.setThrowable(gse); continue; } /* * Certificate is good. * If cert completes the path, * process userCheckers that don't support forward checking * and process policies over whole path * and backtrack appropriately if there is a failure * else if cert does not complete the path, * add it to the path */ if (builder.isPathCompleted(cert)) { if (debug != null) debug.println( "SunCertPathBuilder.depthFirstSearchForward()" + ": commencing final verification"); List<X509Certificate> appendedCerts = new ArrayList<>(cpList); /* * if the trust anchor selected is specified as a trusted * public key rather than a trusted cert, then verify this * cert (which is signed by the trusted public key), but * don't add it yet to the cpList */ if (builder.trustAnchor.getTrustedCert() == null) { appendedCerts.add(0, cert); } Set<String> initExpPolSet = Collections.singleton(PolicyChecker.ANY_POLICY); PolicyNodeImpl rootNode = new PolicyNodeImpl(null, PolicyChecker.ANY_POLICY, null, false, initExpPolSet, false); List<PKIXCertPathChecker> checkers = new ArrayList<>(); PolicyChecker policyChecker = new PolicyChecker( buildParams.initialPolicies(), appendedCerts.size(), buildParams.explicitPolicyRequired(), buildParams.policyMappingInhibited(), buildParams.anyPolicyInhibited(), buildParams.policyQualifiersRejected(), rootNode); checkers.add(policyChecker); // add the algorithm checker checkers.add(new AlgorithmChecker(builder.trustAnchor)); BasicChecker basicChecker = null; if (nextState.keyParamsNeeded()) { PublicKey rootKey = cert.getPublicKey(); if (builder.trustAnchor.getTrustedCert() == null) { rootKey = builder.trustAnchor.getCAPublicKey(); if (debug != null) debug.println( "SunCertPathBuilder.depthFirstSearchForward " + "using buildParams public key: " + rootKey.toString()); } TrustAnchor anchor = new TrustAnchor(cert.getSubjectX500Principal(), rootKey, null); // add the basic checker basicChecker = new BasicChecker(anchor, buildParams.date(), buildParams.sigProvider(), true); checkers.add(basicChecker); } buildParams.setCertPath(cf.generateCertPath(appendedCerts)); boolean revCheckerAdded = false; List<PKIXCertPathChecker> ckrs = buildParams.certPathCheckers(); for (PKIXCertPathChecker ckr : ckrs) { if (ckr instanceof PKIXRevocationChecker) { if (revCheckerAdded) { throw new CertPathValidatorException( "Only one PKIXRevocationChecker can be specified"); } revCheckerAdded = true; // if it's our own, initialize it if (ckr instanceof RevocationChecker) { ((RevocationChecker) ckr).init(builder.trustAnchor, buildParams); } } } // only add a RevocationChecker if revocation is enabled and // a PKIXRevocationChecker has not already been added if (buildParams.revocationEnabled() && !revCheckerAdded) { checkers.add(new RevocationChecker(builder.trustAnchor, buildParams)); } checkers.addAll(ckrs); // Why we don't need BasicChecker and RevocationChecker // if nextState.keyParamsNeeded() is false? for (int i = 0; i < appendedCerts.size(); i++) { X509Certificate currCert = appendedCerts.get(i); if (debug != null) debug.println("current subject = " + currCert.getSubjectX500Principal()); Set<String> unresCritExts = currCert.getCriticalExtensionOIDs(); if (unresCritExts == null) { unresCritExts = Collections.<String>emptySet(); } for (PKIXCertPathChecker currChecker : checkers) { if (!currChecker.isForwardCheckingSupported()) { if (i == 0) { currChecker.init(false); // The user specified // AlgorithmChecker may not be // able to set the trust anchor until now. if (currChecker instanceof AlgorithmChecker) { ((AlgorithmChecker) currChecker).trySetTrustAnchor(builder.trustAnchor); } } try { currChecker.check(currCert, unresCritExts); } catch (CertPathValidatorException cpve) { if (debug != null) debug.println( "SunCertPathBuilder.depthFirstSearchForward(): " + "final verification failed: " + cpve); // If the target cert itself is revoked, we // cannot trust it. We can bail out here. if (buildParams.targetCertConstraints().match(currCert) && cpve.getReason() == BasicReason.REVOKED) { throw cpve; } vertex.setThrowable(cpve); continue vertices; } } } /* * Remove extensions from user checkers that support * forward checking. After this step, we will have * removed all extensions that all user checkers * are capable of processing. */ for (PKIXCertPathChecker checker : buildParams.certPathCheckers()) { if (checker.isForwardCheckingSupported()) { Set<String> suppExts = checker.getSupportedExtensions(); if (suppExts != null) { unresCritExts.removeAll(suppExts); } } } if (!unresCritExts.isEmpty()) { unresCritExts.remove(BasicConstraints_Id.toString()); unresCritExts.remove(NameConstraints_Id.toString()); unresCritExts.remove(CertificatePolicies_Id.toString()); unresCritExts.remove(PolicyMappings_Id.toString()); unresCritExts.remove(PolicyConstraints_Id.toString()); unresCritExts.remove(InhibitAnyPolicy_Id.toString()); unresCritExts.remove(SubjectAlternativeName_Id.toString()); unresCritExts.remove(KeyUsage_Id.toString()); unresCritExts.remove(ExtendedKeyUsage_Id.toString()); if (!unresCritExts.isEmpty()) { throw new CertPathValidatorException( "unrecognized critical extension(s)", null, null, -1, PKIXReason.UNRECOGNIZED_CRIT_EXT); } } } if (debug != null) debug.println( "SunCertPathBuilder.depthFirstSearchForward()" + ": final verification succeeded - path completed!"); pathCompleted = true; /* * if the user specified a trusted public key rather than * trusted certs, then add this cert (which is signed by * the trusted public key) to the cpList */ if (builder.trustAnchor.getTrustedCert() == null) builder.addCertToPath(cert, cpList); // Save the trust anchor this.trustAnchor = builder.trustAnchor; /* * Extract and save the final target public key */ if (basicChecker != null) { finalPublicKey = basicChecker.getPublicKey(); } else { Certificate finalCert; if (cpList.isEmpty()) { finalCert = builder.trustAnchor.getTrustedCert(); } else { finalCert = cpList.getLast(); } finalPublicKey = finalCert.getPublicKey(); } policyTreeResult = policyChecker.getPolicyTree(); return; } else { builder.addCertToPath(cert, cpList); } /* Update the PKIX state */ nextState.updateState(cert); /* * Append an entry for cert in adjacency list and * set index for current vertex. */ adjList.add(new LinkedList<Vertex>()); vertex.setIndex(adjList.size() - 1); /* recursively search for matching certs at next dN */ depthFirstSearchForward(cert.getIssuerX500Principal(), nextState, builder, adjList, cpList); /* * If path has been completed, return ASAP! */ if (pathCompleted) { return; } else { /* * If we get here, it means we have searched all possible * certs issued by the dN w/o finding any matching certs. * This means we have to backtrack to the previous cert in * the path and try some other paths. */ if (debug != null) debug.println("SunCertPathBuilder.depthFirstSearchForward()" + ": backtracking"); builder.removeFinalCertFromPath(cpList); } } }
/** * Describes one step of a certification path build, consisting of a <code>Vertex</code> state * description, a certificate, a possible throwable, and a result code. * * @author Anne Anderson * @since 1.4 * @see sun.security.provider.certpath.Vertex */ public class BuildStep { private static final Debug debug = Debug.getInstance("certpath"); private Vertex vertex; private X509Certificate cert; private Throwable throwable; private int result; /** * result code associated with a certificate that may continue a path from the current * certificate. */ public static final int POSSIBLE = 1; /** * result code associated with a certificate that was tried, but that represents an unsuccessful * path, so the certificate has been backed out to allow backtracking to the next possible path. */ public static final int BACK = 2; /** * result code associated with a certificate that successfully continues the current path, but * does not yet reach the target. */ public static final int FOLLOW = 3; /** * result code associated with a certificate that represents the end of the last possible path, * where no path successfully reached the target. */ public static final int FAIL = 4; /** * result code associated with a certificate that represents the end of a path that successfully * reaches the target. */ public static final int SUCCEED = 5; /** * construct a BuildStep * * @param vtx description of the vertex at this step * @param res result, where result is one of POSSIBLE, BACK, FOLLOW, FAIL, SUCCEED */ public BuildStep(Vertex vtx, int res) { vertex = vtx; if (vertex != null) { cert = (X509Certificate) vertex.getCertificate(); throwable = vertex.getThrowable(); } result = res; } /** * return vertex description for this build step * * @returns Vertex */ public Vertex getVertex() { return vertex; } /** * return the certificate associated with this build step * * @returns X509Certificate */ public X509Certificate getCertificate() { return cert; } /** * return string form of issuer name from certificate associated with this build step * * @returns String form of issuer name or null, if no certificate. */ public String getIssuerName() { return (cert == null ? null : cert.getIssuerX500Principal().toString()); } /** * return string form of issuer name from certificate associated with this build step, or a * default name if no certificate associated with this build step, or if issuer name could not be * obtained from the certificate. * * @param defaultName name to use as default if unable to return an issuer name from the * certificate, or if no certificate. * @returns String form of issuer name or defaultName, if no certificate or exception received * while trying to extract issuer name from certificate. */ public String getIssuerName(String defaultName) { return (cert == null ? defaultName : cert.getIssuerX500Principal().toString()); } /** * return string form of subject name from certificate associated with this build step. * * @returns String form of subject name or null, if no certificate. */ public String getSubjectName() { return (cert == null ? null : cert.getSubjectX500Principal().toString()); } /** * return string form of subject name from certificate associated with this build step, or a * default name if no certificate associated with this build step, or if subject name could not be * obtained from the certificate. * * @param defaultName name to use as default if unable to return a subject name from the * certificate, or if no certificate. * @returns String form of subject name or defaultName, if no certificate or if an exception was * received while attempting to extract the subject name from the certificate. */ public String getSubjectName(String defaultName) { return (cert == null ? defaultName : cert.getSubjectX500Principal().toString()); } /** * return the exception associated with this build step. * * @returns Throwable */ public Throwable getThrowable() { return throwable; } /** * return the result code associated with this build step. The result codes are POSSIBLE, FOLLOW, * BACK, FAIL, SUCCEED. * * @returns int result code */ public int getResult() { return result; } /** * return a string representing the meaning of the result code associated with this build step. * * @param res result code * @returns String string representing meaning of the result code */ public String resultToString(int res) { String resultString = ""; switch (res) { case BuildStep.POSSIBLE: resultString = "Certificate to be tried.\n"; break; case BuildStep.BACK: resultString = "Certificate backed out since path does not " + "satisfy build requirements.\n"; break; case BuildStep.FOLLOW: resultString = "Certificate satisfies conditions.\n"; break; case BuildStep.FAIL: resultString = "Certificate backed out since path does not " + "satisfy conditions.\n"; break; case BuildStep.SUCCEED: resultString = "Certificate satisfies conditions.\n"; break; default: resultString = "Internal error: Invalid step result value.\n"; } return resultString; } /** * return a string representation of this build step, showing minimal detail. * * @returns String */ public String toString() { String out = "Internal Error\n"; switch (result) { case BACK: case FAIL: out = resultToString(result); out = out + vertex.throwableToString(); break; case FOLLOW: case SUCCEED: case POSSIBLE: out = resultToString(result); break; default: out = "Internal Error: Invalid step result\n"; } return out; } /** * return a string representation of this build step, showing all detail of the vertex state * appropriate to the result of this build step, and the certificate contents. * * @returns String */ public String verboseToString() { String out = resultToString(getResult()); switch (result) { case BACK: case FAIL: out = out + vertex.throwableToString(); break; case FOLLOW: case SUCCEED: out = out + vertex.moreToString(); break; case POSSIBLE: break; default: break; } out = out + "Certificate contains:\n" + vertex.certToString(); return out; } /** * return a string representation of this build step, including all possible detail of the vertex * state, but not including the certificate contents. * * @returns String */ public String fullToString() { String out = resultToString(getResult()); out = out + vertex.toString(); return out; } }
/** * This class centralizes all security properties and common security methods. One of its primary * uses is to manage providers. * * @author Benjamin Renaud * @version 1.126, 05/18/04 */ public final class Security { /* Are we debugging? -- for developers */ private static final Debug sdebug = Debug.getInstance("properties"); /* The java.security properties */ private static Properties props; // An element in the cache private static class ProviderProperty { String className; Provider provider; } static { // doPrivileged here because there are multiple // things in initialize that might require privs. // (the FileInputStream call and the File.exists call, // the securityPropFile call, etc) AccessController.doPrivileged( new PrivilegedAction() { public Object run() { initialize(); return null; } }); } private static void initialize() { props = new Properties(); boolean loadedProps = false; boolean overrideAll = false; // first load the system properties file // to determine the value of security.overridePropertiesFile File propFile = securityPropFile("java.security"); if (propFile.exists()) { try { FileInputStream fis = new FileInputStream(propFile); InputStream is = new BufferedInputStream(fis); props.load(is); is.close(); loadedProps = true; if (sdebug != null) { sdebug.println("reading security properties file: " + propFile); } } catch (IOException e) { if (sdebug != null) { sdebug.println("unable to load security properties from " + propFile); e.printStackTrace(); } } } if ("true".equalsIgnoreCase(props.getProperty("security.overridePropertiesFile"))) { String extraPropFile = System.getProperty("java.security.properties"); if (extraPropFile != null && extraPropFile.startsWith("=")) { overrideAll = true; extraPropFile = extraPropFile.substring(1); } if (overrideAll) { props = new Properties(); if (sdebug != null) { sdebug.println("overriding other security properties files!"); } } // now load the user-specified file so its values // will win if they conflict with the earlier values if (extraPropFile != null) { try { URL propURL; extraPropFile = PropertyExpander.expand(extraPropFile); propFile = new File(extraPropFile); if (propFile.exists()) { propURL = new URL("file:" + propFile.getCanonicalPath()); } else { propURL = new URL(extraPropFile); } BufferedInputStream bis = new BufferedInputStream(propURL.openStream()); props.load(bis); bis.close(); loadedProps = true; if (sdebug != null) { sdebug.println("reading security properties file: " + propURL); if (overrideAll) { sdebug.println("overriding other security properties files!"); } } } catch (Exception e) { if (sdebug != null) { sdebug.println("unable to load security properties from " + extraPropFile); e.printStackTrace(); } } } } if (!loadedProps) { initializeStatic(); if (sdebug != null) { sdebug.println("unable to load security properties " + "-- using defaults"); } } } /* * Initialize to default values, if <java.home>/lib/java.security * is not found. */ private static void initializeStatic() { props.put("security.provider.1", "sun.security.provider.Sun"); props.put("security.provider.2", "sun.security.rsa.SunRsaSign"); props.put("security.provider.3", "com.sun.net.ssl.internal.ssl.Provider"); props.put("security.provider.4", "com.sun.crypto.provider.SunJCE"); props.put("security.provider.5", "sun.security.jgss.SunProvider"); props.put("security.provider.6", "com.sun.security.sasl.Provider"); } /** Don't let anyone instantiate this. */ private Security() {} private static File securityPropFile(String filename) { // maybe check for a system property which will specify where to // look. Someday. String sep = File.separator; return new File( System.getProperty("java.home") + sep + "lib" + sep + "security" + sep + filename); } /** * Looks up providers, and returns the property (and its associated provider) mapping the key, if * any. The order in which the providers are looked up is the provider-preference order, as * specificed in the security properties file. */ private static ProviderProperty getProviderProperty(String key) { ProviderProperty entry = null; List providers = Providers.getProviderList().providers(); for (int i = 0; i < providers.size(); i++) { String matchKey = null; Provider prov = (Provider) providers.get(i); String prop = prov.getProperty(key); if (prop == null) { // Is there a match if we do a case-insensitive property name // comparison? Let's try ... for (Enumeration e = prov.keys(); e.hasMoreElements() && prop == null; ) { matchKey = (String) e.nextElement(); if (key.equalsIgnoreCase(matchKey)) { prop = prov.getProperty(matchKey); break; } } } if (prop != null) { ProviderProperty newEntry = new ProviderProperty(); newEntry.className = prop; newEntry.provider = prov; return newEntry; } } return entry; } /** Returns the property (if any) mapping the key for the given provider. */ private static String getProviderProperty(String key, Provider provider) { String prop = provider.getProperty(key); if (prop == null) { // Is there a match if we do a case-insensitive property name // comparison? Let's try ... for (Enumeration e = provider.keys(); e.hasMoreElements() && prop == null; ) { String matchKey = (String) e.nextElement(); if (key.equalsIgnoreCase(matchKey)) { prop = provider.getProperty(matchKey); break; } } } return prop; } /** * Gets a specified property for an algorithm. The algorithm name should be a standard name. See * Appendix A in the <a href= "../../../guide/security/CryptoSpec.html#AppA"> Java Cryptography * Architecture API Specification & Reference </a> for information about standard algorithm * names. One possible use is by specialized algorithm parsers, which may map classes to * algorithms which they understand (much like Key parsers do). * * @param algName the algorithm name. * @param propName the name of the property to get. * @return the value of the specified property. * @deprecated This method used to return the value of a proprietary property in the master file * of the "SUN" Cryptographic Service Provider in order to determine how to parse * algorithm-specific parameters. Use the new provider-based and algorithm-independent <code> * AlgorithmParameters</code> and <code>KeyFactory</code> engine classes (introduced in the * Java 2 platform) instead. */ @Deprecated public static String getAlgorithmProperty(String algName, String propName) { ProviderProperty entry = getProviderProperty("Alg." + propName + "." + algName); if (entry != null) { return entry.className; } else { return null; } } /** * Adds a new provider, at a specified position. The position is the preference order in which * providers are searched for requested algorithms. Note that it is not guaranteed that this * preference will be respected. The position is 1-based, that is, 1 is most preferred, followed * by 2, and so on. * * <p>If the given provider is installed at the requested position, the provider that used to be * at that position, and all providers with a position greater than <code>position</code>, are * shifted up one position (towards the end of the list of installed providers). * * <p>A provider cannot be added if it is already installed. * * <p>First, if there is a security manager, its <code>checkSecurityAccess</code> method is called * with the string <code>"insertProvider."+provider.getName()</code> to see if it's ok to add a * new provider. If the default implementation of <code>checkSecurityAccess</code> is used (i.e., * that method is not overriden), then this will result in a call to the security manager's <code> * checkPermission</code> method with a <code> * SecurityPermission("insertProvider."+provider.getName())</code> permission. * * @param provider the provider to be added. * @param position the preference position that the caller would like for this provider. * @return the actual preference position in which the provider was added, or -1 if the provider * was not added because it is already installed. * @throws NullPointerException if provider is null * @throws SecurityException if a security manager exists and its <code>{@link * java.lang.SecurityManager#checkSecurityAccess}</code> method denies access to add a * new provider * @see #getProvider * @see #removeProvider * @see java.security.SecurityPermission */ public static synchronized int insertProviderAt(Provider provider, int position) { String providerName = provider.getName(); check("insertProvider." + providerName); ProviderList list = Providers.getFullProviderList(); ProviderList newList = ProviderList.insertAt(list, provider, position - 1); if (list == newList) { return -1; } Providers.setProviderList(newList); return newList.getIndex(providerName) + 1; } /** * Adds a provider to the next position available. * * <p>First, if there is a security manager, its <code>checkSecurityAccess</code> method is called * with the string <code>"insertProvider."+provider.getName()</code> to see if it's ok to add a * new provider. If the default implementation of <code>checkSecurityAccess</code> is used (i.e., * that method is not overriden), then this will result in a call to the security manager's <code> * checkPermission</code> method with a <code> * SecurityPermission("insertProvider."+provider.getName())</code> permission. * * @param provider the provider to be added. * @return the preference position in which the provider was added, or -1 if the provider was not * added because it is already installed. * @throws NullPointerException if provider is null * @throws SecurityException if a security manager exists and its <code>{@link * java.lang.SecurityManager#checkSecurityAccess}</code> method denies access to add a * new provider * @see #getProvider * @see #removeProvider * @see java.security.SecurityPermission */ public static int addProvider(Provider provider) { /* * We can't assign a position here because the statically * registered providers may not have been installed yet. * insertProviderAt() will fix that value after it has * loaded the static providers. */ return insertProviderAt(provider, 0); } /** * Removes the provider with the specified name. * * <p>When the specified provider is removed, all providers located at a position greater than * where the specified provider was are shifted down one position (towards the head of the list of * installed providers). * * <p>This method returns silently if the provider is not installed or if name is null. * * <p>First, if there is a security manager, its <code>checkSecurityAccess</code> method is called * with the string <code>"removeProvider."+name</code> to see if it's ok to remove the provider. * If the default implementation of <code>checkSecurityAccess</code> is used (i.e., that method is * not overriden), then this will result in a call to the security manager's <code>checkPermission * </code> method with a <code>SecurityPermission("removeProvider."+name)</code> permission. * * @param name the name of the provider to remove. * @throws SecurityException if a security manager exists and its <code>{@link * java.lang.SecurityManager#checkSecurityAccess}</code> method denies access to remove * the provider * @see #getProvider * @see #addProvider */ public static synchronized void removeProvider(String name) { check("removeProvider." + name); ProviderList list = Providers.getFullProviderList(); ProviderList newList = ProviderList.remove(list, name); Providers.setProviderList(newList); } /** * Returns an array containing all the installed providers. The order of the providers in the * array is their preference order. * * @return an array of all the installed providers. */ public static Provider[] getProviders() { return Providers.getFullProviderList().toArray(); } /** * Returns the provider installed with the specified name, if any. Returns null if no provider * with the specified name is installed or if name is null. * * @param name the name of the provider to get. * @return the provider of the specified name. * @see #removeProvider * @see #addProvider */ public static Provider getProvider(String name) { return Providers.getProviderList().getProvider(name); } /** * Returns an array containing all installed providers that satisfy the specified selection * criterion, or null if no such providers have been installed. The returned providers are ordered * according to their <a href= "#insertProviderAt(java.security.Provider, int)">preference * order</a>. * * <p>A cryptographic service is always associated with a particular algorithm or type. For * example, a digital signature service is always associated with a particular algorithm (e.g., * DSA), and a CertificateFactory service is always associated with a particular certificate type * (e.g., X.509). * * <p>The selection criterion must be specified in one of the following two formats: * * <ul> * <li><i><crypto_service>.<algorithm_or_type></i> * <p>The cryptographic service name must not contain any dots. * <p>A provider satisfies the specified selection criterion iff the provider implements the * specified algorithm or type for the specified cryptographic service. * <p>For example, "CertificateFactory.X.509" would be satisfied by any provider that * supplied a CertificateFactory implementation for X.509 certificates. * <li><i><crypto_service>.<algorithm_or_type> <attribute_name>:< * attribute_value></i> * <p>The cryptographic service name must not contain any dots. There must be one or more * space charaters between the the <i><algorithm_or_type></i> and the * <i><attribute_name></i>. * <p>A provider satisfies this selection criterion iff the provider implements the * specified algorithm or type for the specified cryptographic service and its * implementation meets the constraint expressed by the specified attribute name/value pair. * <p>For example, "Signature.SHA1withDSA KeySize:1024" would be satisfied by any provider * that implemented the SHA1withDSA signature algorithm with a keysize of 1024 (or larger). * </ul> * * <p>See Appendix A in the <a href= "../../../guide/security/CryptoSpec.html#AppA"> Java * Cryptogaphy Architecture API Specification & Reference </a> for information about standard * cryptographic service names, standard algorithm names and standard attribute names. * * @param filter the criterion for selecting providers. The filter is case-insensitive. * @return all the installed providers that satisfy the selection criterion, or null if no such * providers have been installed. * @throws InvalidParameterException if the filter is not in the required format * @throws NullPointerException if filter is null * @see #getProviders(java.util.Map) */ public static Provider[] getProviders(String filter) { String key = null; String value = null; int index = filter.indexOf(':'); if (index == -1) { key = filter; value = ""; } else { key = filter.substring(0, index); value = filter.substring(index + 1); } Hashtable hashtableFilter = new Hashtable(1); hashtableFilter.put(key, value); return (getProviders(hashtableFilter)); } /** * Returns an array containing all installed providers that satisfy the specified* selection * criteria, or null if no such providers have been installed. The returned providers are ordered * according to their <a href= "#insertProviderAt(java.security.Provider, int)">preference * order</a>. * * <p>The selection criteria are represented by a map. Each map entry represents a selection * criterion. A provider is selected iff it satisfies all selection criteria. The key for any * entry in such a map must be in one of the following two formats: * * <ul> * <li><i><crypto_service>.<algorithm_or_type></i> * <p>The cryptographic service name must not contain any dots. * <p>The value associated with the key must be an empty string. * <p>A provider satisfies this selection criterion iff the provider implements the * specified algorithm or type for the specified cryptographic service. * <li><i><crypto_service>.<algorithm_or_type> <attribute_name></i> * <p>The cryptographic service name must not contain any dots. There must be one or more * space charaters between the <i><algorithm_or_type></i> and the * <i><attribute_name></i>. * <p>The value associated with the key must be a non-empty string. A provider satisfies * this selection criterion iff the provider implements the specified algorithm or type for * the specified cryptographic service and its implementation meets the constraint expressed * by the specified attribute name/value pair. * </ul> * * <p>See Appendix A in the <a href= "../../../guide/security/CryptoSpec.html#AppA"> Java * Cryptogaphy Architecture API Specification & Reference </a> for information about standard * cryptographic service names, standard algorithm names and standard attribute names. * * @param filter the criteria for selecting providers. The filter is case-insensitive. * @return all the installed providers that satisfy the selection criteria, or null if no such * providers have been installed. * @throws InvalidParameterException if the filter is not in the required format * @throws NullPointerException if filter is null * @see #getProviders(java.lang.String) */ public static Provider[] getProviders(Map<String, String> filter) { // Get all installed providers first. // Then only return those providers who satisfy the selection criteria. Provider[] allProviders = Security.getProviders(); Set keySet = filter.keySet(); LinkedHashSet candidates = new LinkedHashSet(5); // Returns all installed providers // if the selection criteria is null. if ((keySet == null) || (allProviders == null)) { return allProviders; } boolean firstSearch = true; // For each selection criterion, remove providers // which don't satisfy the criterion from the candidate set. for (Iterator ite = keySet.iterator(); ite.hasNext(); ) { String key = (String) ite.next(); String value = (String) filter.get(key); LinkedHashSet newCandidates = getAllQualifyingCandidates(key, value, allProviders); if (firstSearch) { candidates = newCandidates; firstSearch = false; } if ((newCandidates != null) && !newCandidates.isEmpty()) { // For each provider in the candidates set, if it // isn't in the newCandidate set, we should remove // it from the candidate set. for (Iterator cansIte = candidates.iterator(); cansIte.hasNext(); ) { Provider prov = (Provider) cansIte.next(); if (!newCandidates.contains(prov)) { cansIte.remove(); } } } else { candidates = null; break; } } if ((candidates == null) || (candidates.isEmpty())) return null; Object[] candidatesArray = candidates.toArray(); Provider[] result = new Provider[candidatesArray.length]; for (int i = 0; i < result.length; i++) { result[i] = (Provider) candidatesArray[i]; } return result; } // Map containing cached Spi Class objects of the specified type private static final Map<String, Class> spiMap = new ConcurrentHashMap<String, Class>(); /** * Return the Class object for the given engine type (e.g. "MessageDigest"). Works for Spis in the * java.security package only. */ private static Class getSpiClass(String type) { Class clazz = spiMap.get(type); if (clazz != null) { return clazz; } try { clazz = Class.forName("java.security." + type + "Spi"); spiMap.put(type, clazz); return clazz; } catch (ClassNotFoundException e) { throw (Error) new AssertionError("Spi class not found").initCause(e); } } /* * Returns an array of objects: the first object in the array is * an instance of an implementation of the requested algorithm * and type, and the second object in the array identifies the provider * of that implementation. * The <code>provider</code> argument can be null, in which case all * configured providers will be searched in order of preference. */ static Object[] getImpl(String algorithm, String type, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { if (provider == null) { return GetInstance.getInstance(type, getSpiClass(type), algorithm).toArray(); } else { return GetInstance.getInstance(type, getSpiClass(type), algorithm, provider).toArray(); } } static Object[] getImpl(String algorithm, String type, String provider, Object params) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException { if (provider == null) { return GetInstance.getInstance(type, getSpiClass(type), algorithm, params).toArray(); } else { return GetInstance.getInstance(type, getSpiClass(type), algorithm, params, provider) .toArray(); } } /* * Returns an array of objects: the first object in the array is * an instance of an implementation of the requested algorithm * and type, and the second object in the array identifies the provider * of that implementation. * The <code>provider</code> argument cannot be null. */ static Object[] getImpl(String algorithm, String type, Provider provider) throws NoSuchAlgorithmException { return GetInstance.getInstance(type, getSpiClass(type), algorithm, provider).toArray(); } static Object[] getImpl(String algorithm, String type, Provider provider, Object params) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { return GetInstance.getInstance(type, getSpiClass(type), algorithm, params, provider).toArray(); } /** * Gets a security property value. * * <p>First, if there is a security manager, its <code>checkPermission</code> method is called * with a <code>java.security.SecurityPermission("getProperty."+key)</code> permission to see if * it's ok to retrieve the specified security property value.. * * @param key the key of the property being retrieved. * @return the value of the security property corresponding to key. * @throws SecurityException if a security manager exists and its <code>{@link * java.lang.SecurityManager#checkPermission}</code> method denies access to retrieve the * specified security property value * @throws NullPointerException is key is null * @see #setProperty * @see java.security.SecurityPermission */ public static String getProperty(String key) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new SecurityPermission("getProperty." + key)); } String name = props.getProperty(key); if (name != null) name = name.trim(); // could be a class name with trailing ws return name; } /** * Sets a security property value. * * <p>First, if there is a security manager, its <code>checkPermission</code> method is called * with a <code>java.security.SecurityPermission("setProperty."+key)</code> permission to see if * it's ok to set the specified security property value. * * @param key the name of the property to be set. * @param datum the value of the property to be set. * @throws SecurityException if a security manager exists and its <code>{@link * java.lang.SecurityManager#checkPermission}</code> method denies access to set the * specified security property value * @throws NullPointerException if key or datum is null * @see #getProperty * @see java.security.SecurityPermission */ public static void setProperty(String key, String datum) { check("setProperty." + key); props.put(key, datum); invalidateSMCache(key); /* See below. */ } /* * Implementation detail: If the property we just set in * setProperty() was either "package.access" or * "package.definition", we need to signal to the SecurityManager * class that the value has just changed, and that it should * invalidate it's local cache values. * * Rather than create a new API entry for this function, * we use reflection to set a private variable. */ private static void invalidateSMCache(String key) { final boolean pa = key.equals("package.access"); final boolean pd = key.equals("package.definition"); if (pa || pd) { AccessController.doPrivileged( new PrivilegedAction() { public Object run() { try { /* Get the class via the bootstrap class loader. */ Class cl = Class.forName("java.lang.SecurityManager", false, null); Field f = null; boolean accessible = false; if (pa) { f = cl.getDeclaredField("packageAccessValid"); accessible = f.isAccessible(); f.setAccessible(true); } else { f = cl.getDeclaredField("packageDefinitionValid"); accessible = f.isAccessible(); f.setAccessible(true); } f.setBoolean(f, false); f.setAccessible(accessible); } catch (Exception e1) { /* If we couldn't get the class, it hasn't * been loaded yet. If there is no such * field, we shouldn't try to set it. There * shouldn't be a security execption, as we * are loaded by boot class loader, and we * are inside a doPrivileged() here. * * NOOP: don't do anything... */ } return null; } /* run */ }); /* PrivilegedAction */ } /* if */ } private static void check(String directive) { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkSecurityAccess(directive); } } /* * Returns all providers who satisfy the specified * criterion. */ private static LinkedHashSet getAllQualifyingCandidates( String filterKey, String filterValue, Provider[] allProviders) { String[] filterComponents = getFilterComponents(filterKey, filterValue); // The first component is the service name. // The second is the algorithm name. // If the third isn't null, that is the attrinute name. String serviceName = filterComponents[0]; String algName = filterComponents[1]; String attrName = filterComponents[2]; return getProvidersNotUsingCache(serviceName, algName, attrName, filterValue, allProviders); } private static LinkedHashSet getProvidersNotUsingCache( String serviceName, String algName, String attrName, String filterValue, Provider[] allProviders) { LinkedHashSet candidates = new LinkedHashSet(5); for (int i = 0; i < allProviders.length; i++) { if (isCriterionSatisfied(allProviders[i], serviceName, algName, attrName, filterValue)) { candidates.add(allProviders[i]); } } return candidates; } /* * Returns true if the given provider satisfies * the selection criterion key:value. */ private static boolean isCriterionSatisfied( Provider prov, String serviceName, String algName, String attrName, String filterValue) { String key = serviceName + '.' + algName; if (attrName != null) { key += ' ' + attrName; } // Check whether the provider has a property // whose key is the same as the given key. String propValue = getProviderProperty(key, prov); if (propValue == null) { // Check whether we have an alias instead // of a standard name in the key. String standardName = getProviderProperty("Alg.Alias." + serviceName + "." + algName, prov); if (standardName != null) { key = serviceName + "." + standardName; if (attrName != null) { key += ' ' + attrName; } propValue = getProviderProperty(key, prov); } if (propValue == null) { // The provider doesn't have the given // key in its property list. return false; } } // If the key is in the format of: // <crypto_service>.<algorithm_or_type>, // there is no need to check the value. if (attrName == null) { return true; } // If we get here, the key must be in the // format of <crypto_service>.<algorithm_or_provider> <attribute_name>. if (isStandardAttr(attrName)) { return isConstraintSatisfied(attrName, filterValue, propValue); } else { return filterValue.equalsIgnoreCase(propValue); } } /* * Returns true if the attribute is a standard attribute; * otherwise, returns false. */ private static boolean isStandardAttr(String attribute) { // For now, we just have two standard attributes: // KeySize and ImplementedIn. if (attribute.equalsIgnoreCase("KeySize")) return true; if (attribute.equalsIgnoreCase("ImplementedIn")) return true; return false; } /* * Returns true if the requested attribute value is supported; * otherwise, returns false. */ private static boolean isConstraintSatisfied(String attribute, String value, String prop) { // For KeySize, prop is the max key size the // provider supports for a specific <crypto_service>.<algorithm>. if (attribute.equalsIgnoreCase("KeySize")) { int requestedSize = Integer.parseInt(value); int maxSize = Integer.parseInt(prop); if (requestedSize <= maxSize) { return true; } else { return false; } } // For Type, prop is the type of the implementation // for a specific <crypto service>.<algorithm>. if (attribute.equalsIgnoreCase("ImplementedIn")) { return value.equalsIgnoreCase(prop); } return false; } static String[] getFilterComponents(String filterKey, String filterValue) { int algIndex = filterKey.indexOf('.'); if (algIndex < 0) { // There must be a dot in the filter, and the dot // shouldn't be at the beginning of this string. throw new InvalidParameterException("Invalid filter"); } String serviceName = filterKey.substring(0, algIndex); String algName = null; String attrName = null; if (filterValue.length() == 0) { // The filterValue is an empty string. So the filterKey // should be in the format of <crypto_service>.<algorithm_or_type>. algName = filterKey.substring(algIndex + 1).trim(); if (algName.length() == 0) { // There must be a algorithm or type name. throw new InvalidParameterException("Invalid filter"); } } else { // The filterValue is a non-empty string. So the filterKey must be // in the format of // <crypto_service>.<algorithm_or_type> <attribute_name> int attrIndex = filterKey.indexOf(' '); if (attrIndex == -1) { // There is no attribute name in the filter. throw new InvalidParameterException("Invalid filter"); } else { attrName = filterKey.substring(attrIndex + 1).trim(); if (attrName.length() == 0) { // There is no attribute name in the filter. throw new InvalidParameterException("Invalid filter"); } } // There must be an algorithm name in the filter. if ((attrIndex < algIndex) || (algIndex == attrIndex - 1)) { throw new InvalidParameterException("Invalid filter"); } else { algName = filterKey.substring(algIndex + 1, attrIndex); } } String[] result = new String[3]; result[0] = serviceName; result[1] = algName; result[2] = attrName; return result; } /** * Returns a Set of Strings containing the names of all available algorithms or types for the * specified Java cryptographic service (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore). * Returns an empty Set if there is no provider that supports the specified service or if * serviceName is null. For a complete list of Java cryptographic services, please see the <a * href="../../../guide/security/CryptoSpec.html">Java Cryptography Architecture API Specification * & Reference</a>. Note: the returned set is immutable. * * @param serviceName the name of the Java cryptographic service (e.g., Signature, MessageDigest, * Cipher, Mac, KeyStore). Note: this parameter is case-insensitive. * @return a Set of Strings containing the names of all available algorithms or types for the * specified Java cryptographic service or an empty set if no provider supports the specified * service. * @since 1.4 */ public static Set<String> getAlgorithms(String serviceName) { if ((serviceName == null) || (serviceName.length() == 0) || (serviceName.endsWith("."))) { return Collections.EMPTY_SET; } HashSet result = new HashSet(); Provider[] providers = Security.getProviders(); for (int i = 0; i < providers.length; i++) { // Check the keys for each provider. for (Enumeration e = providers[i].keys(); e.hasMoreElements(); ) { String currentKey = ((String) e.nextElement()).toUpperCase(); if (currentKey.startsWith(serviceName.toUpperCase())) { // We should skip the currentKey if it contains a // whitespace. The reason is: such an entry in the // provider property contains attributes for the // implementation of an algorithm. We are only interested // in entries which lead to the implementation // classes. if (currentKey.indexOf(" ") < 0) { result.add(currentKey.substring(serviceName.length() + 1)); } } } } return Collections.unmodifiableSet(result); } }
/** * Verifies a matching certificate. * * <p>This method executes any of the validation steps in the PKIX path validation algorithm which * were not satisfied via filtering out non-compliant certificates with certificate matching * rules. * * <p>If the last certificate is being verified (the one whose subject matches the target subject, * then the steps in Section 6.1.4 of the Certification Path Validation algorithm are NOT * executed, regardless of whether or not the last cert is an end-entity cert or not. This allows * callers to certify CA certs as well as EE certs. * * @param cert the certificate to be verified * @param currentState the current state against which the cert is verified * @param certPathList the certPathList generated thus far */ void verifyCert(X509Certificate cert, State currState, List certPathList) throws GeneralSecurityException { if (debug != null) debug.println( "ReverseBuilder.verifyCert(SN: " + Debug.toHexString(cert.getSerialNumber()) + "\n Subject: " + cert.getSubjectX500Principal() + ")"); ReverseState currentState = (ReverseState) currState; /* we don't perform any validation of the trusted cert */ if (currentState.isInitial()) { return; } /* * check for looping - abort a loop if * ((we encounter the same certificate twice) AND * ((policyMappingInhibited = true) OR (no policy mapping * extensions can be found between the occurences of the same * certificate))) * in order to facilitate the check to see if there are * any policy mapping extensions found between the occurences * of the same certificate, we reverse the certpathlist first */ if ((certPathList != null) && (!certPathList.isEmpty())) { List reverseCertList = new ArrayList(); Iterator iter = certPathList.iterator(); while (iter.hasNext()) { reverseCertList.add(0, iter.next()); } Iterator cpListIter = reverseCertList.iterator(); boolean policyMappingFound = false; while (cpListIter.hasNext()) { X509Certificate cpListCert = (X509Certificate) cpListIter.next(); X509CertImpl cpListCertImpl = X509CertImpl.toImpl(cpListCert); PolicyMappingsExtension policyMappingsExt = cpListCertImpl.getPolicyMappingsExtension(); if (policyMappingsExt != null) { policyMappingFound = true; } if (debug != null) debug.println("policyMappingFound = " + policyMappingFound); if (cert.equals(cpListCert)) { if ((buildParams.isPolicyMappingInhibited()) || (!policyMappingFound)) { if (debug != null) debug.println("loop detected!!"); throw new CertPathValidatorException("loop detected"); } } } } /* check if target cert */ boolean finalCert = cert.getSubjectX500Principal().equals(targetSubjectDN); /* check if CA cert */ boolean caCert = (cert.getBasicConstraints() != -1 ? true : false); /* if there are more certs to follow, verify certain constraints */ if (!finalCert) { /* check if CA cert */ if (!caCert) throw new CertPathValidatorException("cert is NOT a CA cert"); /* If the certificate was not self-issued, verify that * remainingCerts is greater than zero */ if ((currentState.remainingCACerts <= 0) && !X509CertImpl.isSelfIssued(cert)) { throw new CertPathValidatorException("pathLenConstraint violated, path too long"); } /* * Check keyUsage extension (only if CA cert and not final cert) */ KeyChecker.verifyCAKeyUsage(cert); } else { /* * If final cert, check that it satisfies specified target * constraints */ if (targetCertSelector.match(cert) == false) { throw new CertPathValidatorException("target certificate " + "constraints check failed"); } } /* * Check revocation. */ if (buildParams.isRevocationEnabled()) { boolean crlSign = currentState.crlChecker.check(cert, currentState.pubKey, true); // if this cert can't vouch for the CRL on the next cert, and // if this wasn't the last cert in the chain, then we can't // keep going from here! // NOTE: if we ever add indirect/idp support, this will have // to change... if ((!crlSign) && (!finalCert)) throw new CertPathValidatorException("cert can't vouch for crl"); } /* Check name constraints if this is not a self-issued cert */ if (finalCert || !X509CertImpl.isSelfIssued(cert)) { if (currentState.nc != null) { try { if (!currentState.nc.verify(cert)) { throw new CertPathValidatorException("name constraints check failed"); } } catch (IOException ioe) { throw new CertPathValidatorException(ioe); } } } /* * Check policy */ X509CertImpl certImpl = X509CertImpl.toImpl(cert); currentState.rootNode = PolicyChecker.processPolicies( currentState.certIndex, initPolicies, currentState.explicitPolicy, currentState.policyMapping, currentState.inhibitAnyPolicy, buildParams.getPolicyQualifiersRejected(), currentState.rootNode, certImpl, finalCert); /* * Check CRITICAL private extensions */ Set unresolvedCritExts = cert.getCriticalExtensionOIDs(); if (unresolvedCritExts == null) { unresolvedCritExts = Collections.EMPTY_SET; } Iterator i = currentState.userCheckers.iterator(); while (i.hasNext()) { PKIXCertPathChecker checker = (PKIXCertPathChecker) i.next(); checker.check(cert, unresolvedCritExts); } /* * Look at the remaining extensions and remove any ones we have * already checked. If there are any left, throw an exception! */ if (!unresolvedCritExts.isEmpty()) { unresolvedCritExts.remove(PKIXExtensions.BasicConstraints_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.NameConstraints_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.CertificatePolicies_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.PolicyMappings_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.PolicyConstraints_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.InhibitAnyPolicy_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.SubjectAlternativeName_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.KeyUsage_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.ExtendedKeyUsage_Id.toString()); if (!unresolvedCritExts.isEmpty()) throw new CertificateException("Unrecognized critical extension(s)"); } /* * Check signature. */ if (buildParams.getSigProvider() != null) { cert.verify(currentState.pubKey, buildParams.getSigProvider()); } else { cert.verify(currentState.pubKey); } }
/** * This class builds certification paths in the forward direction. * * <p>If successful, it returns a certification path which has successfully satisfied all the * constraints and requirements specified in the PKIXBuilderParameters object and has been validated * according to the PKIX path validation algorithm defined in RFC 3280. * * <p>This implementation uses a depth-first search approach to finding certification paths. If it * comes to a point in which it cannot find any more certificates leading to the target OR the path * length is too long it backtracks to previous paths until the target has been found or all * possible paths have been exhausted. * * <p>This implementation is not thread-safe. * * @since 1.4 * @author Sean Mullan * @author Yassir Elley */ public final class SunCertPathBuilder extends CertPathBuilderSpi { private static final Debug debug = Debug.getInstance("certpath"); /* * private objects shared by methods */ private BuilderParams buildParams; private CertificateFactory cf; private boolean pathCompleted = false; private PolicyNode policyTreeResult; private TrustAnchor trustAnchor; private PublicKey finalPublicKey; /** * Create an instance of <code>SunCertPathBuilder</code>. * * @throws CertPathBuilderException if an error occurs */ public SunCertPathBuilder() throws CertPathBuilderException { try { cf = CertificateFactory.getInstance("X.509"); } catch (CertificateException e) { throw new CertPathBuilderException(e); } } @Override public CertPathChecker engineGetRevocationChecker() { return new RevocationChecker(); } /** * Attempts to build a certification path using the Sun build algorithm from a trusted anchor(s) * to a target subject, which must both be specified in the input parameter set. This method will * attempt to build in the forward direction: from the target to the CA. * * <p>The certification path that is constructed is validated according to the PKIX specification. * * @param params the parameter set for building a path. Must be an instance of <code> * PKIXBuilderParameters</code>. * @return a certification path builder result. * @exception CertPathBuilderException Exception thrown if builder is unable to build a complete * certification path from the trusted anchor(s) to the target subject. * @throws InvalidAlgorithmParameterException if the given parameters are inappropriate for this * certification path builder. */ @Override public CertPathBuilderResult engineBuild(CertPathParameters params) throws CertPathBuilderException, InvalidAlgorithmParameterException { if (debug != null) { debug.println("SunCertPathBuilder.engineBuild(" + params + ")"); } buildParams = PKIX.checkBuilderParams(params); return build(); } private PKIXCertPathBuilderResult build() throws CertPathBuilderException { List<List<Vertex>> adjList = new ArrayList<>(); PKIXCertPathBuilderResult result = buildCertPath(false, adjList); if (result == null) { if (debug != null) { debug.println( "SunCertPathBuilder.engineBuild: 2nd pass; " + "try building again searching all certstores"); } // try again adjList.clear(); result = buildCertPath(true, adjList); if (result == null) { throw new SunCertPathBuilderException( "unable to find valid " + "certification path to requested target", new AdjacencyList(adjList)); } } return result; } private PKIXCertPathBuilderResult buildCertPath( boolean searchAllCertStores, List<List<Vertex>> adjList) throws CertPathBuilderException { // Init shared variables and build certification path pathCompleted = false; trustAnchor = null; finalPublicKey = null; policyTreeResult = null; LinkedList<X509Certificate> certPathList = new LinkedList<>(); try { buildForward(adjList, certPathList, searchAllCertStores); } catch (GeneralSecurityException | IOException e) { if (debug != null) { debug.println("SunCertPathBuilder.engineBuild() exception in " + "build"); e.printStackTrace(); } throw new SunCertPathBuilderException( "unable to find valid " + "certification path to requested target", e, new AdjacencyList(adjList)); } // construct SunCertPathBuilderResult try { if (pathCompleted) { if (debug != null) debug.println("SunCertPathBuilder.engineBuild() " + "pathCompleted"); // we must return a certpath which has the target // as the first cert in the certpath - i.e. reverse // the certPathList Collections.reverse(certPathList); return new SunCertPathBuilderResult( cf.generateCertPath(certPathList), trustAnchor, policyTreeResult, finalPublicKey, new AdjacencyList(adjList)); } } catch (CertificateException e) { if (debug != null) { debug.println("SunCertPathBuilder.engineBuild() exception " + "in wrap-up"); e.printStackTrace(); } throw new SunCertPathBuilderException( "unable to find valid " + "certification path to requested target", e, new AdjacencyList(adjList)); } return null; } /* * Private build forward method. */ private void buildForward( List<List<Vertex>> adjacencyList, LinkedList<X509Certificate> certPathList, boolean searchAllCertStores) throws GeneralSecurityException, IOException { if (debug != null) { debug.println("SunCertPathBuilder.buildForward()..."); } /* Initialize current state */ ForwardState currentState = new ForwardState(); currentState.initState(buildParams.certPathCheckers()); /* Initialize adjacency list */ adjacencyList.clear(); adjacencyList.add(new LinkedList<Vertex>()); currentState.untrustedChecker = new UntrustedChecker(); depthFirstSearchForward( buildParams.targetSubject(), currentState, new ForwardBuilder(buildParams, searchAllCertStores), adjacencyList, certPathList); } /* * This method performs a depth first search for a certification * path while building forward which meets the requirements set in * the parameters object. * It uses an adjacency list to store all certificates which were * tried (i.e. at one time added to the path - they may not end up in * the final path if backtracking occurs). This information can * be used later to debug or demo the build. * * See "Data Structure and Algorithms, by Aho, Hopcroft, and Ullman" * for an explanation of the DFS algorithm. * * @param dN the distinguished name being currently searched for certs * @param currentState the current PKIX validation state */ private void depthFirstSearchForward( X500Principal dN, ForwardState currentState, ForwardBuilder builder, List<List<Vertex>> adjList, LinkedList<X509Certificate> cpList) throws GeneralSecurityException, IOException { if (debug != null) { debug.println( "SunCertPathBuilder.depthFirstSearchForward(" + dN + ", " + currentState.toString() + ")"); } /* * Find all the certificates issued to dN which * satisfy the PKIX certification path constraints. */ Collection<X509Certificate> certs = builder.getMatchingCerts(currentState, buildParams.certStores()); List<Vertex> vertices = addVertices(certs, adjList); if (debug != null) { debug.println( "SunCertPathBuilder.depthFirstSearchForward(): " + "certs.size=" + vertices.size()); } /* * For each cert in the collection, verify anything * that hasn't been checked yet (signature, revocation, etc) * and check for loops. Call depthFirstSearchForward() * recursively for each good cert. */ vertices: for (Vertex vertex : vertices) { /** * Restore state to currentState each time through the loop. This is important because some of * the user-defined checkers modify the state, which MUST be restored if the cert eventually * fails to lead to the target and the next matching cert is tried. */ ForwardState nextState = (ForwardState) currentState.clone(); X509Certificate cert = vertex.getCertificate(); try { builder.verifyCert(cert, nextState, cpList); } catch (GeneralSecurityException gse) { if (debug != null) { debug.println( "SunCertPathBuilder.depthFirstSearchForward()" + ": validation failed: " + gse); gse.printStackTrace(); } vertex.setThrowable(gse); continue; } /* * Certificate is good. * If cert completes the path, * process userCheckers that don't support forward checking * and process policies over whole path * and backtrack appropriately if there is a failure * else if cert does not complete the path, * add it to the path */ if (builder.isPathCompleted(cert)) { if (debug != null) debug.println( "SunCertPathBuilder.depthFirstSearchForward()" + ": commencing final verification"); List<X509Certificate> appendedCerts = new ArrayList<>(cpList); /* * if the trust anchor selected is specified as a trusted * public key rather than a trusted cert, then verify this * cert (which is signed by the trusted public key), but * don't add it yet to the cpList */ if (builder.trustAnchor.getTrustedCert() == null) { appendedCerts.add(0, cert); } Set<String> initExpPolSet = Collections.singleton(PolicyChecker.ANY_POLICY); PolicyNodeImpl rootNode = new PolicyNodeImpl(null, PolicyChecker.ANY_POLICY, null, false, initExpPolSet, false); List<PKIXCertPathChecker> checkers = new ArrayList<>(); PolicyChecker policyChecker = new PolicyChecker( buildParams.initialPolicies(), appendedCerts.size(), buildParams.explicitPolicyRequired(), buildParams.policyMappingInhibited(), buildParams.anyPolicyInhibited(), buildParams.policyQualifiersRejected(), rootNode); checkers.add(policyChecker); // add the algorithm checker checkers.add(new AlgorithmChecker(builder.trustAnchor)); BasicChecker basicChecker = null; if (nextState.keyParamsNeeded()) { PublicKey rootKey = cert.getPublicKey(); if (builder.trustAnchor.getTrustedCert() == null) { rootKey = builder.trustAnchor.getCAPublicKey(); if (debug != null) debug.println( "SunCertPathBuilder.depthFirstSearchForward " + "using buildParams public key: " + rootKey.toString()); } TrustAnchor anchor = new TrustAnchor(cert.getSubjectX500Principal(), rootKey, null); // add the basic checker basicChecker = new BasicChecker(anchor, buildParams.date(), buildParams.sigProvider(), true); checkers.add(basicChecker); } buildParams.setCertPath(cf.generateCertPath(appendedCerts)); boolean revCheckerAdded = false; List<PKIXCertPathChecker> ckrs = buildParams.certPathCheckers(); for (PKIXCertPathChecker ckr : ckrs) { if (ckr instanceof PKIXRevocationChecker) { if (revCheckerAdded) { throw new CertPathValidatorException( "Only one PKIXRevocationChecker can be specified"); } revCheckerAdded = true; // if it's our own, initialize it if (ckr instanceof RevocationChecker) { ((RevocationChecker) ckr).init(builder.trustAnchor, buildParams); } } } // only add a RevocationChecker if revocation is enabled and // a PKIXRevocationChecker has not already been added if (buildParams.revocationEnabled() && !revCheckerAdded) { checkers.add(new RevocationChecker(builder.trustAnchor, buildParams)); } checkers.addAll(ckrs); // Why we don't need BasicChecker and RevocationChecker // if nextState.keyParamsNeeded() is false? for (int i = 0; i < appendedCerts.size(); i++) { X509Certificate currCert = appendedCerts.get(i); if (debug != null) debug.println("current subject = " + currCert.getSubjectX500Principal()); Set<String> unresCritExts = currCert.getCriticalExtensionOIDs(); if (unresCritExts == null) { unresCritExts = Collections.<String>emptySet(); } for (PKIXCertPathChecker currChecker : checkers) { if (!currChecker.isForwardCheckingSupported()) { if (i == 0) { currChecker.init(false); // The user specified // AlgorithmChecker may not be // able to set the trust anchor until now. if (currChecker instanceof AlgorithmChecker) { ((AlgorithmChecker) currChecker).trySetTrustAnchor(builder.trustAnchor); } } try { currChecker.check(currCert, unresCritExts); } catch (CertPathValidatorException cpve) { if (debug != null) debug.println( "SunCertPathBuilder.depthFirstSearchForward(): " + "final verification failed: " + cpve); // If the target cert itself is revoked, we // cannot trust it. We can bail out here. if (buildParams.targetCertConstraints().match(currCert) && cpve.getReason() == BasicReason.REVOKED) { throw cpve; } vertex.setThrowable(cpve); continue vertices; } } } /* * Remove extensions from user checkers that support * forward checking. After this step, we will have * removed all extensions that all user checkers * are capable of processing. */ for (PKIXCertPathChecker checker : buildParams.certPathCheckers()) { if (checker.isForwardCheckingSupported()) { Set<String> suppExts = checker.getSupportedExtensions(); if (suppExts != null) { unresCritExts.removeAll(suppExts); } } } if (!unresCritExts.isEmpty()) { unresCritExts.remove(BasicConstraints_Id.toString()); unresCritExts.remove(NameConstraints_Id.toString()); unresCritExts.remove(CertificatePolicies_Id.toString()); unresCritExts.remove(PolicyMappings_Id.toString()); unresCritExts.remove(PolicyConstraints_Id.toString()); unresCritExts.remove(InhibitAnyPolicy_Id.toString()); unresCritExts.remove(SubjectAlternativeName_Id.toString()); unresCritExts.remove(KeyUsage_Id.toString()); unresCritExts.remove(ExtendedKeyUsage_Id.toString()); if (!unresCritExts.isEmpty()) { throw new CertPathValidatorException( "unrecognized critical extension(s)", null, null, -1, PKIXReason.UNRECOGNIZED_CRIT_EXT); } } } if (debug != null) debug.println( "SunCertPathBuilder.depthFirstSearchForward()" + ": final verification succeeded - path completed!"); pathCompleted = true; /* * if the user specified a trusted public key rather than * trusted certs, then add this cert (which is signed by * the trusted public key) to the cpList */ if (builder.trustAnchor.getTrustedCert() == null) builder.addCertToPath(cert, cpList); // Save the trust anchor this.trustAnchor = builder.trustAnchor; /* * Extract and save the final target public key */ if (basicChecker != null) { finalPublicKey = basicChecker.getPublicKey(); } else { Certificate finalCert; if (cpList.isEmpty()) { finalCert = builder.trustAnchor.getTrustedCert(); } else { finalCert = cpList.getLast(); } finalPublicKey = finalCert.getPublicKey(); } policyTreeResult = policyChecker.getPolicyTree(); return; } else { builder.addCertToPath(cert, cpList); } /* Update the PKIX state */ nextState.updateState(cert); /* * Append an entry for cert in adjacency list and * set index for current vertex. */ adjList.add(new LinkedList<Vertex>()); vertex.setIndex(adjList.size() - 1); /* recursively search for matching certs at next dN */ depthFirstSearchForward(cert.getIssuerX500Principal(), nextState, builder, adjList, cpList); /* * If path has been completed, return ASAP! */ if (pathCompleted) { return; } else { /* * If we get here, it means we have searched all possible * certs issued by the dN w/o finding any matching certs. * This means we have to backtrack to the previous cert in * the path and try some other paths. */ if (debug != null) debug.println("SunCertPathBuilder.depthFirstSearchForward()" + ": backtracking"); builder.removeFinalCertFromPath(cpList); } } } /* * Adds a collection of matching certificates to the * adjacency list. */ private static List<Vertex> addVertices( Collection<X509Certificate> certs, List<List<Vertex>> adjList) { List<Vertex> l = adjList.get(adjList.size() - 1); for (X509Certificate cert : certs) { Vertex v = new Vertex(cert); l.add(v); } return l; } /** Returns true if trust anchor certificate matches specified certificate constraints. */ private static boolean anchorIsTarget(TrustAnchor anchor, CertSelector sel) { X509Certificate anchorCert = anchor.getTrustedCert(); if (anchorCert != null) { return sel.match(anchorCert); } return false; } }