
2005-02-17 Andrew John Hughes <gnu_andrew@member.fsf.org> Michael Koch <konqueror@gmx.de> * gnu/java/net/protocol/http/Cookie.java, gnu/java/net/protocol/http/HTTPConnection.java, gnu/java/net/protocol/http/HTTPDateFormat.java, gnu/java/net/protocol/http/Request.java, gnu/java/nio/PipeImpl.java, gnu/java/rmi/dgc/DGCImpl.java, gnu/java/rmi/server/ConnectionRunnerPool.java, gnu/java/rmi/server/UnicastConnectionManager.java, gnu/java/security/der/DERWriter.java, gnu/java/security/pkcs/SignerInfo.java, gnu/java/security/provider/EncodedKeyFactory.java, gnu/java/security/provider/GnuDHPublicKey.java, gnu/java/security/provider/GnuDSAPrivateKey.java, gnu/java/security/provider/GnuDSAPublicKey.java, gnu/java/security/provider/PKIXCertPathValidatorImpl.java, gnu/java/security/x509/X500DistinguishedName.java, gnu/java/security/x509/X509CRL.java, gnu/java/security/x509/X509CRLEntry.java, gnu/java/security/x509/X509Certificate.java, gnu/java/security/x509/ext/AuthorityKeyIdentifier.java, gnu/java/security/x509/ext/CertificatePolicies.java, gnu/java/security/x509/ext/PolicyConstraint.java, gnu/xml/dom/Consumer.java, gnu/xml/dom/DomCharacterData.java, gnu/xml/dom/DomDocument.java, gnu/xml/dom/DomDocumentBuilder.java, gnu/xml/dom/DomIterator.java, gnu/xml/dom/DomNode.java, gnu/xml/dom/DomXPathExpression.java, gnu/xml/dom/DomXPathResult.java, gnu/xml/dom/JAXPFactory.java, gnu/xml/pipeline/CallFilter.java, gnu/xml/pipeline/DomConsumer.java, gnu/xml/pipeline/LinkFilter.java, gnu/xml/pipeline/NSFilter.java, gnu/xml/pipeline/TeeConsumer.java, gnu/xml/pipeline/ValidationConsumer.java, gnu/xml/pipeline/WellFormednessFilter.java, gnu/xml/pipeline/XIncludeFilter.java, gnu/xml/pipeline/XsltFilter.java, gnu/xml/transform/ApplyImportsNode.java, gnu/xml/transform/Bindings.java, gnu/xml/transform/DocumentFunction.java, gnu/xml/transform/FormatNumberFunction.java, gnu/xml/transform/NodeNumberNode.java, gnu/xml/transform/NumberNode.java, gnu/xml/transform/Stylesheet.java, gnu/xml/transform/SystemPropertyFunction.java, gnu/xml/transform/Template.java, gnu/xml/transform/TemplatesImpl.java, gnu/xml/transform/TransformerImpl.java, gnu/xml/transform/ValueOfNode.java, gnu/xml/transform/XSLURIResolver.java, gnu/xml/util/DoParse.java, gnu/xml/util/Resolver.java, gnu/xml/xpath/Expr.java, gnu/xml/xpath/FunctionCall.java, gnu/xml/xpath/RelationalExpr.java, gnu/xml/xpath/Selector.java, gnu/xml/xpath/XPathParser.java: Reworked import statements, fixed modifier order and some little formatting issues. Co-Authored-By: Michael Koch <konqueror@gmx.de> From-SVN: r95177
704 lines
24 KiB
Java
704 lines
24 KiB
Java
/* PKIXCertPathValidatorImpl.java -- PKIX certificate path validator.
|
|
Copyright (C) 2004 Free Software Foundation, Inc.
|
|
|
|
This file is part of GNU Classpath.
|
|
|
|
GNU Classpath is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2, or (at your option)
|
|
any later version.
|
|
|
|
GNU Classpath is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GNU Classpath; see the file COPYING. If not, write to the
|
|
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
02111-1307 USA.
|
|
|
|
Linking this library statically or dynamically with other modules is
|
|
making a combined work based on this library. Thus, the terms and
|
|
conditions of the GNU General Public License cover the whole
|
|
combination.
|
|
|
|
As a special exception, the copyright holders of this library give you
|
|
permission to link this library with independent modules to produce an
|
|
executable, regardless of the license terms of these independent
|
|
modules, and to copy and distribute the resulting executable under
|
|
terms of your choice, provided that you also meet, for each linked
|
|
independent module, the terms and conditions of the license of that
|
|
module. An independent module is a module which is not derived from
|
|
or based on this library. If you modify this library, you may extend
|
|
this exception to your version of the library, but you are not
|
|
obligated to do so. If you do not wish to do so, delete this
|
|
exception statement from your version. */
|
|
|
|
|
|
package gnu.java.security.provider;
|
|
|
|
import gnu.java.security.OID;
|
|
import gnu.java.security.x509.GnuPKIExtension;
|
|
import gnu.java.security.x509.PolicyNodeImpl;
|
|
import gnu.java.security.x509.X509CertSelectorImpl;
|
|
import gnu.java.security.x509.X509CRLSelectorImpl;
|
|
import gnu.java.security.x509.ext.BasicConstraints;
|
|
import gnu.java.security.x509.ext.CertificatePolicies;
|
|
import gnu.java.security.x509.ext.Extension;
|
|
import gnu.java.security.x509.ext.KeyUsage;
|
|
import gnu.java.security.x509.ext.PolicyConstraint;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.security.InvalidAlgorithmParameterException;
|
|
import java.security.InvalidKeyException;
|
|
import java.security.PublicKey;
|
|
|
|
import java.security.cert.CertificateException;
|
|
import java.security.cert.CertPath;
|
|
import java.security.cert.CertPathParameters;
|
|
import java.security.cert.CertPathValidatorException;
|
|
import java.security.cert.CertPathValidatorResult;
|
|
import java.security.cert.CertPathValidatorSpi;
|
|
import java.security.cert.CertStore;
|
|
import java.security.cert.CertStoreException;
|
|
import java.security.cert.CRL;
|
|
import java.security.cert.PKIXCertPathChecker;
|
|
import java.security.cert.PKIXCertPathValidatorResult;
|
|
import java.security.cert.PKIXParameters;
|
|
import java.security.cert.TrustAnchor;
|
|
import java.security.cert.X509Certificate;
|
|
import java.security.cert.X509CRL;
|
|
import java.security.interfaces.DSAParams;
|
|
import java.security.interfaces.DSAPublicKey;
|
|
|
|
import java.util.Arrays;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.Date;
|
|
import java.util.HashSet;
|
|
import java.util.Iterator;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
|
|
/**
|
|
* An implementation of the Public Key Infrastructure's X.509
|
|
* certificate path validation algorithm.
|
|
*
|
|
* <p>See <a href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280:
|
|
* Internet X.509 Public Key Infrastructure Certificate and
|
|
* Certificate Revocation List (CRL) Profile</a>.
|
|
*
|
|
* @author Casey Marshall (rsdio@metastatic.org)
|
|
*/
|
|
public class PKIXCertPathValidatorImpl extends CertPathValidatorSpi
|
|
{
|
|
|
|
// Constants.
|
|
// -------------------------------------------------------------------------
|
|
|
|
private static final boolean DEBUG = false;
|
|
private static void debug (String msg)
|
|
{
|
|
System.err.print (">> PKIXCertPathValidatorImpl: ");
|
|
System.err.println (msg);
|
|
}
|
|
|
|
public static final String ANY_POLICY = "2.5.29.32.0";
|
|
|
|
// Constructor.
|
|
// -------------------------------------------------------------------------
|
|
|
|
public PKIXCertPathValidatorImpl()
|
|
{
|
|
super();
|
|
}
|
|
|
|
// Instance methods.
|
|
// -------------------------------------------------------------------------
|
|
|
|
public CertPathValidatorResult engineValidate(CertPath path,
|
|
CertPathParameters params)
|
|
throws CertPathValidatorException, InvalidAlgorithmParameterException
|
|
{
|
|
if (!(params instanceof PKIXParameters))
|
|
throw new InvalidAlgorithmParameterException("not a PKIXParameters object");
|
|
|
|
// First check if the certificate path is valid.
|
|
//
|
|
// This means that:
|
|
//
|
|
// (a) for all x in {1, ..., n-1}, the subject of certificate x is
|
|
// the issuer of certificate x+1;
|
|
//
|
|
// (b) for all x in {1, ..., n}, the certificate was valid at the
|
|
// time in question.
|
|
//
|
|
// Because this is the X.509 algorithm, we also check if all
|
|
// cerificates are of type X509Certificate.
|
|
|
|
PolicyNodeImpl rootNode = new PolicyNodeImpl();
|
|
Set initPolicies = ((PKIXParameters) params).getInitialPolicies();
|
|
rootNode.setValidPolicy(ANY_POLICY);
|
|
rootNode.setCritical(false);
|
|
rootNode.setDepth(0);
|
|
if (initPolicies != null)
|
|
rootNode.addAllExpectedPolicies(initPolicies);
|
|
else
|
|
rootNode.addExpectedPolicy(ANY_POLICY);
|
|
List checks = ((PKIXParameters) params).getCertPathCheckers();
|
|
List l = path.getCertificates();
|
|
if (l == null || l.size() == 0)
|
|
throw new CertPathValidatorException();
|
|
X509Certificate[] p = null;
|
|
try
|
|
{
|
|
p = (X509Certificate[]) l.toArray(new X509Certificate[l.size()]);
|
|
}
|
|
catch (ClassCastException cce)
|
|
{
|
|
throw new CertPathValidatorException("invalid certificate path");
|
|
}
|
|
|
|
String sigProvider = ((PKIXParameters) params).getSigProvider();
|
|
PublicKey prevKey = null;
|
|
Date now = ((PKIXParameters) params).getDate();
|
|
if (now == null)
|
|
now = new Date();
|
|
LinkedList policyConstraints = new LinkedList();
|
|
for (int i = p.length - 1; i >= 0; i--)
|
|
{
|
|
try
|
|
{
|
|
p[i].checkValidity(now);
|
|
}
|
|
catch (CertificateException ce)
|
|
{
|
|
throw new CertPathValidatorException(ce.toString());
|
|
}
|
|
Set uce = getCritExts(p[i]);
|
|
for (Iterator check = checks.iterator(); check.hasNext(); )
|
|
{
|
|
try
|
|
{
|
|
((PKIXCertPathChecker) check.next()).check(p[i], uce);
|
|
}
|
|
catch (Exception x)
|
|
{
|
|
}
|
|
}
|
|
|
|
PolicyConstraint constr = null;
|
|
if (p[i] instanceof GnuPKIExtension)
|
|
{
|
|
Extension pcx =
|
|
((GnuPKIExtension) p[i]).getExtension (PolicyConstraint.ID);
|
|
if (pcx != null)
|
|
constr = (PolicyConstraint) pcx.getValue();
|
|
}
|
|
else
|
|
{
|
|
byte[] pcx = p[i].getExtensionValue (PolicyConstraint.ID.toString());
|
|
if (pcx != null)
|
|
{
|
|
try
|
|
{
|
|
constr = new PolicyConstraint (pcx);
|
|
}
|
|
catch (Exception x)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
if (constr != null && constr.getRequireExplicitPolicy() >= 0)
|
|
{
|
|
policyConstraints.add (new int[]
|
|
{ p.length-i, constr.getRequireExplicitPolicy() });
|
|
}
|
|
|
|
updatePolicyTree(p[i], rootNode, p.length-i, (PKIXParameters) params,
|
|
checkExplicitPolicy (p.length-i, policyConstraints));
|
|
|
|
// The rest of the tests involve this cert's relationship with the
|
|
// next in the path. If this cert is the end entity, we can stop.
|
|
if (i == 0)
|
|
break;
|
|
|
|
basicSanity(p, i);
|
|
PublicKey pubKey = null;
|
|
try
|
|
{
|
|
pubKey = p[i].getPublicKey();
|
|
if (pubKey instanceof DSAPublicKey)
|
|
{
|
|
DSAParams dsa = ((DSAPublicKey) pubKey).getParams();
|
|
// If the DSA public key is missing its parameters, use those
|
|
// from the previous cert's key.
|
|
if (dsa == null || dsa.getP() == null || dsa.getG() == null
|
|
|| dsa.getQ() == null)
|
|
{
|
|
if (prevKey == null)
|
|
throw new InvalidKeyException("DSA keys not chainable");
|
|
if (!(prevKey instanceof DSAPublicKey))
|
|
throw new InvalidKeyException("DSA keys not chainable");
|
|
dsa = ((DSAPublicKey) prevKey).getParams();
|
|
pubKey = new GnuDSAPublicKey(((DSAPublicKey) pubKey).getY(),
|
|
dsa.getP(), dsa.getQ(), dsa.getG());
|
|
}
|
|
}
|
|
if (sigProvider == null)
|
|
p[i-1].verify(pubKey);
|
|
else
|
|
p[i-1].verify(pubKey, sigProvider);
|
|
prevKey = pubKey;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
throw new CertPathValidatorException(e.toString());
|
|
}
|
|
if (!p[i].getSubjectDN().equals(p[i-1].getIssuerDN()))
|
|
throw new CertPathValidatorException("issuer DN mismatch");
|
|
boolean[] issuerUid = p[i-1].getIssuerUniqueID();
|
|
boolean[] subjectUid = p[i].getSubjectUniqueID();
|
|
if (issuerUid != null && subjectUid != null)
|
|
if (!Arrays.equals(issuerUid, subjectUid))
|
|
throw new CertPathValidatorException("UID mismatch");
|
|
|
|
// Check the certificate against the revocation lists.
|
|
if (((PKIXParameters) params).isRevocationEnabled())
|
|
{
|
|
X509CRLSelectorImpl selector = new X509CRLSelectorImpl();
|
|
try
|
|
{
|
|
selector.addIssuerName(p[i].getSubjectDN());
|
|
}
|
|
catch (IOException ioe)
|
|
{
|
|
throw new CertPathValidatorException("error selecting CRLs");
|
|
}
|
|
List certStores = ((PKIXParameters) params).getCertStores();
|
|
List crls = new LinkedList();
|
|
for (Iterator it = certStores.iterator(); it.hasNext(); )
|
|
{
|
|
CertStore cs = (CertStore) it.next();
|
|
try
|
|
{
|
|
Collection c = cs.getCRLs(selector);
|
|
crls.addAll(c);
|
|
}
|
|
catch (CertStoreException cse)
|
|
{
|
|
}
|
|
}
|
|
if (crls.isEmpty())
|
|
throw new CertPathValidatorException("no CRLs for issuer");
|
|
boolean certOk = false;
|
|
for (Iterator it = crls.iterator(); it.hasNext(); )
|
|
{
|
|
CRL crl = (CRL) it.next();
|
|
if (!(crl instanceof X509CRL))
|
|
continue;
|
|
X509CRL xcrl = (X509CRL) crl;
|
|
if (!checkCRL(xcrl, p, now, p[i], pubKey, certStores))
|
|
continue;
|
|
if (xcrl.isRevoked(p[i-1]))
|
|
throw new CertPathValidatorException("certificate is revoked");
|
|
else
|
|
certOk = true;
|
|
}
|
|
if (!certOk)
|
|
throw new CertPathValidatorException("certificate's validity could not be determined");
|
|
}
|
|
}
|
|
rootNode.setReadOnly();
|
|
|
|
// Now ensure that the first certificate in the chain was issued
|
|
// by a trust anchor.
|
|
Exception cause = null;
|
|
Set anchors = ((PKIXParameters) params).getTrustAnchors();
|
|
for (Iterator i = anchors.iterator(); i.hasNext(); )
|
|
{
|
|
TrustAnchor anchor = (TrustAnchor) i.next();
|
|
X509Certificate anchorCert = null;
|
|
PublicKey anchorKey = null;
|
|
if (anchor.getTrustedCert() != null)
|
|
{
|
|
anchorCert = anchor.getTrustedCert();
|
|
anchorKey = anchorCert.getPublicKey();
|
|
}
|
|
else
|
|
anchorKey = anchor.getCAPublicKey();
|
|
if (anchorKey == null)
|
|
continue;
|
|
try
|
|
{
|
|
if (anchorCert == null)
|
|
anchorCert.checkValidity(now);
|
|
p[p.length-1].verify(anchorKey);
|
|
if (anchorCert != null && anchorCert.getBasicConstraints() >= 0
|
|
&& anchorCert.getBasicConstraints() < p.length)
|
|
continue;
|
|
|
|
if (((PKIXParameters) params).isRevocationEnabled())
|
|
{
|
|
X509CRLSelectorImpl selector = new X509CRLSelectorImpl();
|
|
if (anchorCert != null)
|
|
try
|
|
{
|
|
selector.addIssuerName(anchorCert.getSubjectDN());
|
|
}
|
|
catch (IOException ioe)
|
|
{
|
|
}
|
|
else
|
|
selector.addIssuerName(anchor.getCAName());
|
|
List certStores = ((PKIXParameters) params).getCertStores();
|
|
List crls = new LinkedList();
|
|
for (Iterator it = certStores.iterator(); it.hasNext(); )
|
|
{
|
|
CertStore cs = (CertStore) it.next();
|
|
try
|
|
{
|
|
Collection c = cs.getCRLs(selector);
|
|
crls.addAll(c);
|
|
}
|
|
catch (CertStoreException cse)
|
|
{
|
|
}
|
|
}
|
|
if (crls.isEmpty())
|
|
continue;
|
|
for (Iterator it = crls.iterator(); it.hasNext(); )
|
|
{
|
|
CRL crl = (CRL) it.next();
|
|
if (!(crl instanceof X509CRL))
|
|
continue;
|
|
X509CRL xcrl = (X509CRL) crl;
|
|
try
|
|
{
|
|
xcrl.verify(anchorKey);
|
|
}
|
|
catch (Exception x)
|
|
{
|
|
continue;
|
|
}
|
|
Date nextUpdate = xcrl.getNextUpdate();
|
|
if (nextUpdate != null && nextUpdate.compareTo(now) < 0)
|
|
continue;
|
|
if (xcrl.isRevoked(p[p.length-1]))
|
|
throw new CertPathValidatorException("certificate is revoked");
|
|
}
|
|
}
|
|
|
|
// The chain is valid; return the result.
|
|
return new PKIXCertPathValidatorResult(anchor, rootNode,
|
|
p[0].getPublicKey());
|
|
}
|
|
catch (Exception ignored)
|
|
{
|
|
cause = ignored;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// The path is not valid.
|
|
CertPathValidatorException cpve =
|
|
new CertPathValidatorException("path validation failed");
|
|
if (cause != null)
|
|
cpve.initCause (cause);
|
|
throw cpve;
|
|
}
|
|
|
|
// Own methods.
|
|
// -------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Check if a given CRL is acceptable for checking the revocation status
|
|
* of certificates in the path being checked.
|
|
*
|
|
* <p>The CRL is accepted iff:</p>
|
|
*
|
|
* <ol>
|
|
* <li>The <i>nextUpdate</i> field (if present) is in the future.</li>
|
|
* <li>The CRL does not contain any unsupported critical extensions.</li>
|
|
* <li>The CRL is signed by one of the certificates in the path, or,</li>
|
|
* <li>The CRL is signed by the given public key and was issued by the
|
|
* public key's subject, or,</li>
|
|
* <li>The CRL is signed by a certificate in the given cert stores, and
|
|
* that cert is signed by one of the certificates in the path.</li>
|
|
* </ol>
|
|
*
|
|
* @param crl The CRL being checked.
|
|
* @param path The path this CRL is being checked against.
|
|
* @param now The value to use as 'now'.
|
|
* @param pubKeySubject The subject of the public key.
|
|
* @param pubKey The public key to check.
|
|
* @return True if the CRL is acceptable.
|
|
*/
|
|
private static boolean checkCRL(X509CRL crl, X509Certificate[] path, Date now,
|
|
X509Certificate pubKeyCert, PublicKey pubKey,
|
|
List certStores)
|
|
{
|
|
Date nextUpdate = crl.getNextUpdate();
|
|
if (nextUpdate != null && nextUpdate.compareTo(now) < 0)
|
|
return false;
|
|
if (crl.hasUnsupportedCriticalExtension())
|
|
return false;
|
|
for (int i = 0; i < path.length; i++)
|
|
{
|
|
if (!path[i].getSubjectDN().equals(crl.getIssuerDN()))
|
|
continue;
|
|
boolean[] keyUsage = path[i].getKeyUsage();
|
|
if (keyUsage != null)
|
|
{
|
|
if (!keyUsage[KeyUsage.CRL_SIGN])
|
|
continue;
|
|
}
|
|
try
|
|
{
|
|
crl.verify(path[i].getPublicKey());
|
|
return true;
|
|
}
|
|
catch (Exception x)
|
|
{
|
|
}
|
|
}
|
|
if (crl.getIssuerDN().equals(pubKeyCert.getSubjectDN()))
|
|
{
|
|
try
|
|
{
|
|
boolean[] keyUsage = pubKeyCert.getKeyUsage();
|
|
if (keyUsage != null)
|
|
{
|
|
if (!keyUsage[KeyUsage.CRL_SIGN])
|
|
throw new Exception();
|
|
}
|
|
crl.verify(pubKey);
|
|
return true;
|
|
}
|
|
catch (Exception x)
|
|
{
|
|
}
|
|
}
|
|
try
|
|
{
|
|
X509CertSelectorImpl select = new X509CertSelectorImpl();
|
|
select.addSubjectName(crl.getIssuerDN());
|
|
List certs = new LinkedList();
|
|
for (Iterator it = certStores.iterator(); it.hasNext(); )
|
|
{
|
|
CertStore cs = (CertStore) it.next();
|
|
try
|
|
{
|
|
certs.addAll(cs.getCertificates(select));
|
|
}
|
|
catch (CertStoreException cse)
|
|
{
|
|
}
|
|
}
|
|
for (Iterator it = certs.iterator(); it.hasNext(); )
|
|
{
|
|
X509Certificate c = (X509Certificate) it.next();
|
|
for (int i = 0; i < path.length; i++)
|
|
{
|
|
if (!c.getIssuerDN().equals(path[i].getSubjectDN()))
|
|
continue;
|
|
boolean[] keyUsage = c.getKeyUsage();
|
|
if (keyUsage != null)
|
|
{
|
|
if (!keyUsage[KeyUsage.CRL_SIGN])
|
|
continue;
|
|
}
|
|
try
|
|
{
|
|
c.verify(path[i].getPublicKey());
|
|
crl.verify(c.getPublicKey());
|
|
return true;
|
|
}
|
|
catch (Exception x)
|
|
{
|
|
}
|
|
}
|
|
if (c.getIssuerDN().equals(pubKeyCert.getSubjectDN()))
|
|
{
|
|
c.verify(pubKey);
|
|
crl.verify(c.getPublicKey());
|
|
}
|
|
}
|
|
}
|
|
catch (Exception x)
|
|
{
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static Set getCritExts(X509Certificate cert)
|
|
{
|
|
HashSet s = new HashSet();
|
|
if (cert instanceof GnuPKIExtension)
|
|
{
|
|
Collection exts = ((GnuPKIExtension) cert).getExtensions();
|
|
for (Iterator it = exts.iterator(); it.hasNext(); )
|
|
{
|
|
Extension ext = (Extension) it.next();
|
|
if (ext.isCritical() && !ext.isSupported())
|
|
s.add(ext.getOid().toString());
|
|
}
|
|
}
|
|
else
|
|
s.addAll(cert.getCriticalExtensionOIDs());
|
|
return s;
|
|
}
|
|
|
|
/**
|
|
* Perform a basic sanity check on the CA certificate at <code>index</code>.
|
|
*/
|
|
private static void basicSanity(X509Certificate[] path, int index)
|
|
throws CertPathValidatorException
|
|
{
|
|
X509Certificate cert = path[index];
|
|
int pathLen = 0;
|
|
for (int i = index - 1; i > 0; i--)
|
|
{
|
|
if (!path[i].getIssuerDN().equals(path[i].getSubjectDN()))
|
|
pathLen++;
|
|
}
|
|
Extension e = null;
|
|
if (cert instanceof GnuPKIExtension)
|
|
{
|
|
e = ((GnuPKIExtension) cert).getExtension(BasicConstraints.ID);
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
e = new Extension(cert.getExtensionValue(BasicConstraints.ID.toString()));
|
|
}
|
|
catch (Exception x)
|
|
{
|
|
}
|
|
}
|
|
if (e == null)
|
|
throw new CertPathValidatorException("no basicConstraints");
|
|
BasicConstraints bc = (BasicConstraints) e.getValue();
|
|
if (!bc.isCA())
|
|
throw new CertPathValidatorException("certificate cannot be used to verify signatures");
|
|
if (bc.getPathLengthConstraint() >= 0 && bc.getPathLengthConstraint() < pathLen)
|
|
throw new CertPathValidatorException("path is too long");
|
|
|
|
boolean[] keyUsage = cert.getKeyUsage();
|
|
if (keyUsage != null)
|
|
{
|
|
if (!keyUsage[KeyUsage.KEY_CERT_SIGN])
|
|
throw new CertPathValidatorException("certificate cannot be used to sign certificates");
|
|
}
|
|
}
|
|
|
|
private static void updatePolicyTree(X509Certificate cert, PolicyNodeImpl root,
|
|
int depth, PKIXParameters params,
|
|
boolean explicitPolicy)
|
|
throws CertPathValidatorException
|
|
{
|
|
if (DEBUG) debug("updatePolicyTree depth == " + depth);
|
|
Set nodes = new HashSet();
|
|
LinkedList stack = new LinkedList();
|
|
Iterator current = null;
|
|
stack.addLast(Collections.singleton(root).iterator());
|
|
do
|
|
{
|
|
current = (Iterator) stack.removeLast();
|
|
while (current.hasNext())
|
|
{
|
|
PolicyNodeImpl p = (PolicyNodeImpl) current.next();
|
|
if (DEBUG) debug("visiting node == " + p);
|
|
if (p.getDepth() == depth - 1)
|
|
{
|
|
if (DEBUG) debug("added node");
|
|
nodes.add(p);
|
|
}
|
|
else
|
|
{
|
|
if (DEBUG) debug("skipped node");
|
|
stack.addLast(current);
|
|
current = p.getChildren();
|
|
}
|
|
}
|
|
}
|
|
while (!stack.isEmpty());
|
|
|
|
Extension e = null;
|
|
CertificatePolicies policies = null;
|
|
List qualifierInfos = null;
|
|
if (cert instanceof GnuPKIExtension)
|
|
{
|
|
e = ((GnuPKIExtension) cert).getExtension(CertificatePolicies.ID);
|
|
if (e != null)
|
|
policies = (CertificatePolicies) e.getValue();
|
|
}
|
|
|
|
List cp = null;
|
|
if (policies != null)
|
|
cp = policies.getPolicies();
|
|
else
|
|
cp = Collections.EMPTY_LIST;
|
|
boolean match = false;
|
|
if (DEBUG) debug("nodes are == " + nodes);
|
|
if (DEBUG) debug("cert policies are == " + cp);
|
|
for (Iterator it = nodes.iterator(); it.hasNext(); )
|
|
{
|
|
PolicyNodeImpl parent = (PolicyNodeImpl) it.next();
|
|
if (DEBUG) debug("adding policies to " + parent);
|
|
for (Iterator it2 = cp.iterator(); it2.hasNext(); )
|
|
{
|
|
OID policy = (OID) it2.next();
|
|
if (DEBUG) debug("trying to add policy == " + policy);
|
|
if (policy.toString().equals(ANY_POLICY) &&
|
|
params.isAnyPolicyInhibited())
|
|
continue;
|
|
PolicyNodeImpl child = new PolicyNodeImpl();
|
|
child.setValidPolicy(policy.toString());
|
|
child.addExpectedPolicy(policy.toString());
|
|
if (parent.getExpectedPolicies().contains(policy.toString()))
|
|
{
|
|
parent.addChild(child);
|
|
match = true;
|
|
}
|
|
else if (parent.getExpectedPolicies().contains(ANY_POLICY))
|
|
{
|
|
parent.addChild(child);
|
|
match = true;
|
|
}
|
|
else if (ANY_POLICY.equals (policy.toString()))
|
|
{
|
|
parent.addChild (child);
|
|
match = true;
|
|
}
|
|
if (match && policies != null)
|
|
{
|
|
List qualifiers = policies.getPolicyQualifierInfos (policy);
|
|
if (qualifiers != null)
|
|
child.addAllPolicyQualifiers (qualifiers);
|
|
}
|
|
}
|
|
}
|
|
if (!match && (params.isExplicitPolicyRequired() || explicitPolicy))
|
|
throw new CertPathValidatorException("policy tree building failed");
|
|
}
|
|
|
|
private boolean checkExplicitPolicy (int depth, List explicitPolicies)
|
|
{
|
|
if (DEBUG) debug ("checkExplicitPolicy depth=" + depth);
|
|
for (Iterator it = explicitPolicies.iterator(); it.hasNext(); )
|
|
{
|
|
int[] i = (int[]) it.next();
|
|
int caDepth = i[0];
|
|
int limit = i[1];
|
|
if (DEBUG) debug (" caDepth=" + caDepth + " limit=" + limit);
|
|
if (depth - caDepth >= limit)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|