FULL PRODUCT VERSION : java version "1.6.0_06" Java(TM) SE Runtime Environment (build 1.6.0_06-b02) Java HotSpot(TM) Client VM (build 10.0-b22, mixed mode, sharing) ADDITIONAL OS VERSION INFORMATION : Microsoft Windows XP [Version 5.1.2600] A DESCRIPTION OF THE PROBLEM : When the CertPathBuilder is requested to create a CertPath leading to an End Entity certificate (specified by BasicConstraints extension), it fails to include the actual End Entity certificate in the chain. STEPS TO FOLLOW TO REPRODUCE THE PROBLEM : See the code sample. REPRODUCIBILITY : This bug can be reproduced always. ---------- BEGIN SOURCE ---------- import java.math.BigInteger; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.Provider; import java.security.PublicKey; import java.security.Security; import java.security.cert.CertPathBuilder; import java.security.cert.CertStore; import java.security.cert.CollectionCertStoreParameters; import java.security.cert.PKIXBuilderParameters; import java.security.cert.PKIXCertPathBuilderResult; import java.security.cert.TrustAnchor; import java.security.cert.X509CertSelector; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.Date; import javax.security.auth.x500.X500Principal; import org.bouncycastle.asn1.x509.BasicConstraints; import org.bouncycastle.asn1.x509.X509Extensions; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.x509.X509V3CertificateGenerator; import sun.security.provider.Sun; public class PKIXBugReport { static Provider bcProvider = new BouncyCastleProvider(); static Provider sunProvider = new Sun(); static { Security.addProvider(bcProvider); Security.addProvider(sunProvider); } static KeyPairGenerator kg; public static void main(String[] args) throws Exception { kg = KeyPairGenerator.getInstance("RSA", bcProvider); KeyPair keyPair = kg.generateKeyPair(); PrivateKey taSigningKey = keyPair.getPrivate(); X509Certificate ta = makeCert("TrustAnchor", null, keyPair.getPublic(), taSigningKey, true); keyPair = kg.generateKeyPair(); PrivateKey caSigningKey = keyPair.getPrivate(); X509Certificate ca = makeCert("CA", ta, keyPair.getPublic(), taSigningKey, true); keyPair = kg.generateKeyPair(); X509Certificate endEntity = makeCert("EndEntity", ca, keyPair.getPublic(), caSigningKey, false); CertStore certStore; { ArrayList<X509Certificate> certs = new ArrayList<X509Certificate>(2); certs.add(ca); certs.add(endEntity); CollectionCertStoreParameters certStoreParams = new CollectionCertStoreParameters(certs); // doesn't make a difference //certStore = CertStore.getInstance("Collection", certStoreParams, bcProvider); certStore = CertStore.getInstance("Collection", certStoreParams, sunProvider); } X509CertSelector certSelector = new X509CertSelector(); certSelector.setBasicConstraints(-2); // end entity only PKIXBuilderParameters builderParams = new PKIXBuilderParameters( Collections.singleton(new TrustAnchor(ta, null)), certSelector); builderParams.setRevocationEnabled(false); builderParams.addCertStore(certStore); { CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", bcProvider); PKIXCertPathBuilderResult buildResult = (PKIXCertPathBuilderResult) builder.build(builderParams); // correctly prints cert path length = 2 System.out.println(buildResult.getCertPath()); } { CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", sunProvider); PKIXCertPathBuilderResult buildResult = (PKIXCertPathBuilderResult) builder.build(builderParams); // incorrectly prints cert path length = 1 System.out.println(buildResult.getCertPath()); } } static long serial = 1L; private static X509Certificate makeCert( String name, X509Certificate parent, PublicKey certKey, PrivateKey signingKey, boolean isCA) throws Exception { X509V3CertificateGenerator cg = new X509V3CertificateGenerator(); X500Principal subjectDN = new X500Principal("CN=" + name); cg.setSubjectDN(subjectDN); if(parent == null) { cg.setIssuerDN(subjectDN); } else { cg.setIssuerDN(parent.getSubjectX500Principal()); } cg.setPublicKey(certKey); Date notBefore = new Date(); cg.setNotBefore(notBefore); Calendar calendar = Calendar.getInstance(); calendar.setTime(notBefore); calendar.add(Calendar.YEAR, 1); cg.setNotAfter(calendar.getTime()); cg.setSerialNumber(BigInteger.valueOf(serial++)); cg.setSignatureAlgorithm("SHA1WithRSA"); cg.addExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(isCA)); X509Certificate cert = cg.generate(signingKey, bcProvider.getName()); return cert; } } ---------- END SOURCE ---------- CUSTOMER SUBMITTED WORKAROUND : Use BouncyCastle implementation of CertPathBuilder, as per the code sample.
|