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

PKIXCertPathBuilder fails for certificates without extensions

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P2 P2
    • 1.4.0
    • 1.4.0
    • security-libs
    • rc1
    • x86
    • windows_2000



      Name: nt126004 Date: 10/25/2001


      java version "1.4.0-beta2"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-beta2-b77)
      Java HotSpot(TM) Client VM (build 1.4.0-beta2-b77, mixed mode)

      When attempting to build a certificate path via the CertPathBuilder class
      (using "PKIX"), if the target certificate does not have the Authority Key
      Identifier extension, a call to the CertPathBuilder build() method results in a
      NullPointerException with no other explanation. It should probably throw a more
      appropriate exception and give a better error message.

      The documentation seems to be OK [for the build(CertPathParameters) method
      of the java.security.cert.CertPathBuilder class]. In particular it says that a
      CertPathBuilderException is thrown "if the builder is unable to construct a certification
      path that satisfies the specified parameters."

      In the case where the target certificate does not have the Authority Key Identifier
      extension, the builder is unable to construct a path, but instead of throwing a
      CertPathBuilderException, a NullPointerException is thrown. So the behavior
      disagrees with the documentation. (Note also that the documentation does not list
      any precondition that the certificate must have the Authority Key Identifier extension).

      Since I don't have access to the JDK1.4 source code, it's hard to tell why a
      NullPointerException is being thrown, but my best guess is that the developer of that
      code may have unconsciously assumed that any target certificate would have the Authority
      Key Identifier extension, and it is simply throwing a NullPointerException when it is not there.

      In summary, I believe the NullPointerException is not the correct response because it does
      not agree with the documentation.

      However, with respect to the documentation, it might be beneficial to point out in the
      documentation that target certificates need to have the Authority Key Identifier extension (although I suppose
      that it is assumed that anyone working the API needs to be familiar with the PKIX specification).

      Source code to reproduce the problem:

      package misc;

      import java.security.cert.X509Certificate;
      import java.security.cert.TrustAnchor;
      import java.security.cert.CollectionCertStoreParameters;
      import java.security.cert.CertStore;
      import java.security.cert.X509CertSelector;
      import java.security.cert.CertPathBuilder;
      import java.security.cert.PKIXBuilderParameters;
      import java.security.cert.CertPathBuilderResult;
      import java.security.cert.CertificateFactory;
      import java.security.cert.CRL;
      import java.security.cert.CertPath;
      import java.util.HashSet;
      import java.util.ArrayList;
      import java.io.ByteArrayInputStream;
      import sun.misc.BASE64Decoder;

      /**
       * This is a simple test class that attempts to make use of the certificate
       * path building API (part of the JDK1.4 Certificate Path API).
       *
       * Potential bug or undesirable feature in JDK:
       * If the certificate does not have the Authority Key Identifier extension, an
       * attempt to build the chain results in a NullPointerException with no other
       * explanation. It should probably throw a more appropriate exception and give
       * a better error message.
       *
       * Instructions:
       * Simply run the class. The first certificate should work. The second one
       * will fail.
       *
       * Configuration:
       * -Windows 2000 Professional
       * -java version "1.4.0-beta2"
       * -Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-beta2-
      b77)
       * -Java HotSpot(TM) Client VM (build 1.4.0-beta2-b77, mixed mode)
       */
      public class Certs {

          public static void main(String[] args) {
              try {
                  Certs certs = new Certs();
                  
                  // the first certificate has the Authority Key Identifier
      extension
                  certs.doBuild(getUserCertificate1());
                  System.out.println("successfully built path for the first
      certificate");
                  System.out.println();
                  System.out.println();
                              
                  // the second certificate does not have the Authority Key
      Identifier extension
                  // this will not succeed
                  certs.doBuild(getUserCertificate2());
                  System.out.println("successfully built path for the second
      certificate");
              } catch (Exception ex) {
                  ex.printStackTrace();
              }
          }
          
          private void doBuild(X509Certificate userCert) throws Exception {
              // get the set of trusted CA certificates (only one in this instance)
              HashSet trustAnchors = new HashSet();
              X509Certificate trustedCert = getTrustedCertificate();
              trustAnchors.add(new TrustAnchor(trustedCert, null));
              
              // put together a CertStore (repository of the certificates and CRLs)
              ArrayList certs = new ArrayList();
              CRL crl = getCRL();
              certs.add(crl);
              certs.add(trustedCert);
              certs.add(userCert);
              CollectionCertStoreParameters certStoreParams = new
      CollectionCertStoreParameters(certs);
              CertStore certStore = CertStore.getInstance("Collection",
      certStoreParams);
                              
              // specify the target certificate via a CertSelector
              X509CertSelector certSelector = new X509CertSelector();
              certSelector.setCertificate(userCert);
              certSelector.setSubject(userCert.getSubjectDN().getName()); // seems to
      be required
                      
              // build a valid cerificate path
              CertPathBuilder certPathBuilder = CertPathBuilder.getInstance
      ("PKIX");
              PKIXBuilderParameters certPathBuilderParams = new PKIXBuilderParameters
      (trustAnchors, certSelector);
              certPathBuilderParams.addCertStore(certStore);
              CertPathBuilderResult result = certPathBuilder.build
      (certPathBuilderParams);
              
              // get and show cert path
              CertPath certPath = result.getCertPath();
              System.out.println(certPath.toString());
          }
                          
          private static X509Certificate getTrustedCertificate() throws Exception
      {
              // this certificate has the Authority Key Identifier extension.
              // it was issued by some other self-signed certificate, but we
              // simply treat this certificate as the trusted one
              String sCert =
                  "-----BEGIN CERTIFICATE-----\n"
                  
      + "MIIBezCCASWgAwIBAgIQyWD8dLUoqpJFyDxrfRlrsTANBgkqhkiG9w0BAQQFADAW\n"
                  
      + "MRQwEgYDVQQDEwtSb290IEFnZW5jeTAeFw0wMTEwMTkxMjU5MjZaFw0zOTEyMzEy\n"
                  
      + "MzU5NTlaMBoxGDAWBgNVBAMTD1Jvb3RDZXJ0aWZpY2F0ZTBcMA0GCSqGSIb3DQEB\n"
                  
      + "AQUAA0sAMEgCQQC+NFKszPjatUZKWmyWaFjir1wB93FX2u5SL+GMjgUsMs1JcTKQ\n"
                  
      + "Kh0cnnQKknNkV4cTW4NPn31YCoB1+0KA3mknAgMBAAGjSzBJMEcGA1UdAQRAMD6A\n"
                  
      + "EBLkCS0GHR1PAI1hIdwWZGOhGDAWMRQwEgYDVQQDEwtSb290IEFnZW5jeYIQBjds\n"
                  
      + "AKoAZIoRz7jUqlw19DANBgkqhkiG9w0BAQQFAANBACJxAfP57yqaT9N+nRgAOugM\n"
                  
      + "JG0aN3/peCIvL3p29epRL2xoWFvxpUUlsH2I39OZ6b8+twWCebhkv1I62segXAk=\n"
                  + "-----END CERTIFICATE-----";
              CertificateFactory certFactory = CertificateFactory.getInstance
      ("X.509");
              ByteArrayInputStream bytes = new ByteArrayInputStream(sCert.getBytes());
              return (X509Certificate)certFactory.generateCertificate(bytes);
          }
          
          private static X509Certificate getUserCertificate1() throws Exception
      {
              // this certificate has the Authority Key Identifier extension.
              String sCert =
                  "-----BEGIN CERTIFICATE-----\n"
                  
      + "MIIBfzCCASmgAwIBAgIQWFSKzCWO2ptOAc2F3MKZSzANBgkqhkiG9w0BAQQFADAa\n"
                  
      + "MRgwFgYDVQQDEw9Sb290Q2VydGlmaWNhdGUwHhcNMDExMDE5MTMwNzQxWhcNMzkx\n"
                  
      + "MjMxMjM1OTU5WjAaMRgwFgYDVQQDEw9Vc2VyQ2VydGlmaWNhdGUwXDANBgkqhkiG\n"
                  
      + "9w0BAQEFAANLADBIAkEA24gypa2YFGZHKznEWWbqIWNVXCM35W7RwJwhGpNsuBCj\n"
                  
      + "NT6KEo66F+OOMgZmb0KrEZHBJASJ3n4Cqbt4aHm/2wIDAQABo0swSTBHBgNVHQEE\n"
                  
      + "QDA+gBBch+eYzOPgVRbMq5vGpVWooRgwFjEUMBIGA1UEAxMLUm9vdCBBZ2VuY3mC\n"
                  
      + "EMlg/HS1KKqSRcg8a30Za7EwDQYJKoZIhvcNAQEEBQADQQCYBIHBqQQJePi5Hzfo\n"
                  
      + "CxeUaYlXmvbxVNkxM65Pplsj3h4ntfZaynmlhahH3YsnnA8wk6xPt04LjSId12RB\n"
                  + "PeuO\n"
                  + "-----END CERTIFICATE-----";
              CertificateFactory certFactory = CertificateFactory.getInstance
      ("X.509");
              ByteArrayInputStream bytes = new ByteArrayInputStream(sCert.getBytes());
              return (X509Certificate)certFactory.generateCertificate(bytes);
          }
           
          private static X509Certificate getUserCertificate2() throws Exception {
              // this certificate DOES NOT have the Authority Key Identifier
      extension.
              String sCert =
                  "-----BEGIN CERTIFICATE-----\n"
                  
      + "MIIBMjCB3aADAgECAhB6225ckZVssEukPuvk1U1PMA0GCSqGSIb3DQEBBAUAMBox\n"
                  
      + "GDAWBgNVBAMTD1Jvb3RDZXJ0aWZpY2F0ZTAeFw0wMTEwMTkxNjA5NTZaFw0wMjEw\n"
                  
      + "MTkyMjA5NTZaMBsxGTAXBgNVBAMTEFVzZXJDZXJ0aWZpY2F0ZTIwXDANBgkqhkiG\n"
                  
      + "9w0BAQEFAANLADBIAkEAzicGiW9aUlUoQIZnLy1l8MMV5OvA+4VJ4T/xo/PpN8Oq\n"
                  
      + "WgZVGKeEp6JCzMlXEJk3TGLfpXL4Ytw+Ldhv0QPhLwIDAnMpMA0GCSqGSIb3DQEB\n"
                  
      + "BAUAA0EAQmj9SFHEx66JyAps3ew4pcSS3QvfVZ/6qsNUYCG75rFGcTUPHcXKql9y\n"
                  + "qBT83iNLJ//krjw5Ju0WRPg/buHSww==\n"
                  + "-----END CERTIFICATE-----";
              CertificateFactory certFactory = CertificateFactory.getInstance
      ("X.509");
              ByteArrayInputStream bytes = new ByteArrayInputStream(sCert.getBytes());
              return (X509Certificate)certFactory.generateCertificate(bytes);
          }
          
          private static CRL getCRL() throws Exception {
              // this crl is empty (nothing on the list)
              String crlBase64 =
                  "MIGdMEkwDQYJKoZIhvcNAQEFBQAwGjEYMBYGA1UEAwwPUm9vdENlcnRpZmljYXRlFw0
      wMTEwMTkx\n"
                  
      + "MzE0MDNaFw0wMTExMDkxNjUwMzBaMA0GCSqGSIb3DQEBBQUAA0EAcVnmwqjhfF9NCcX5Ct14KJamn"
                  
      + "TBiDkxpNCCtJh3902toleJiY6AakPAW+EsqES8q7JvB80GNK0nEpJDWEkVh9ww==";
              BASE64Decoder base64Decoder = new BASE64Decoder();
              byte[] crlBytes = base64Decoder.decodeBuffer(crlBase64);
              ByteArrayInputStream bytes = new ByteArrayInputStream
      (crlBytes);
              CertificateFactory certFactory = CertificateFactory.getInstance
      ("X.509");
              CRL crl = certFactory.generateCRL(bytes);
              return crl;
          }

          
      }

        Program output:

       
      X.509 Cert Path: length = 1.
      [
      =========================================================Certificate 1 start.
      [
      [
        Version: V3
        Subject: CN=UserCertificate
        Signature Algorithm: MD5withRSA, OID = 1.2.840.113549.1.1.4
       
        Key: com.sun.net.ssl.internal.ssl.JSA_RSAPublicKey@aeffdf
        Validity: [From: Fri Oct 19 09:07:41 EDT 2001,
                     To: Sat Dec 31 18:59:59 EST 2039]
        Issuer: CN=RootCertificate
        SerialNumber: [ 58548acc 258eda9b 4e01cd85 dcc2994b ]
       
      Certificate Extensions: 1
      [1]: ObjectId: 2.5.29.1 Criticality=false
      Extension unknown: DER encoded OCTET string =
      0000: 04 40 30 3E 80 10 5C 87 E7 98 CC E3 E0 55 16 CC .@0>..\......U..
      0010: AB 9B C6 A5 55 A8 A1 18 30 16 31 14 30 12 06 03 ....U...0.1.0...
      0020: 55 04 03 13 0B 52 6F 6F 74 20 41 67 65 6E 63 79 U....Root Agency
      0030: 82 10 C9 60 FC 74 B5 28 AA 92 45 C8 3C 6B 7D 19 ...`.t.(..E.<k..
      0040: 6B B1 k.
       
       
      ]
        Algorithm: [MD5withRSA]
        Signature:
      0000: 98 04 81 C1 A9 04 09 78 F8 B9 1F 37 E8 0B 17 94 .......x...7....
      0010: 69 89 57 9A F6 F1 54 D9 31 33 AE 4F A6 5B 23 DE i.W...T.13.O.[#.
      0020: 1E 27 B5 F6 5A CA 79 A5 85 A8 47 DD 8B 27 9C 0F .'..Z.y...G..'..
      0030: 30 93 AC 4F B7 4E 0B 8D 22 1D D7 64 41 3D EB 8E 0..O.N.."..dA=..
       
      ]
      =========================================================Certificate 1 end.
       
       
       
      ]
      successfully built path for the first certificate
       
       
      sun.security.provider.certpath.SunCertPathBuilderException: unable to find
      valid certification path to requested target; internal cause is:
              java.lang.NullPointerException
              at sun.security.provider.certpath.SunCertPathBuilder.engineBuild
      (SunCertPathBuilder.java:196)
              at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:343)
              at misc.Certs.doBuild(Certs.java:84)
              at misc.Certs.main(Certs.java:53)
      Caused by: java.lang.NullPointerException
              at
      sun.security.provider.certpath.SunCertPathBuilder.depthFirstSearchForward
      (SunCertPathBuilder.java:514)
              at
      sun.security.provider.certpath.SunCertPathBuilder.depthFirstSearchForward
      (SunCertPathBuilder.java:577)
              at sun.security.provider.certpath.SunCertPathBuilder.buildForward
      (SunCertPathBuilder.java:315)
              at sun.security.provider.certpath.SunCertPathBuilder.engineBuild
      (SunCertPathBuilder.java:187)
              ... 3 more
      (Review ID: 134101)
      ======================================================================

            andreas Andreas Sterbenz
            nthompsosunw Nathanael Thompson (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: