Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6714842

CertPathBuilder returns incorrect CertPath for BasicConstraints in builderParams

    Details

    • Subcomponent:
    • Resolved In Build:
      b31
    • CPU:
      x86
    • OS:
      windows_xp
    • Verification:
      Verified

      Backports

        Description

        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.

          Activity

          Hide
          mullan Sean Mullan added a comment -
          BT2:EVALUATION

          Yes, this is a bug. The problem was that the implementation was ignoring the
          basic constraints selector parameter and always considering CA
          certificates as a potential target certificate.
          Show
          mullan Sean Mullan added a comment - BT2:EVALUATION Yes, this is a bug. The problem was that the implementation was ignoring the basic constraints selector parameter and always considering CA certificates as a potential target certificate.

            People

            • Assignee:
              mullan Sean Mullan
              Reporter:
              ndcosta Nelson Dcosta
            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:
                Imported:
                Indexed: