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

Handshaker throws NPE if TrustManager returns null from getAcceptedIssuers

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Not an Issue
    • Icon: P4 P4
    • None
    • 7
    • security-libs

      FULL PRODUCT VERSION :
      jdk@ssl-jdk:~$ java -version
      openjdk version "1.7.0-internal-fastdebug"
      OpenJDK Runtime Environment (build 1.7.0-internal-fastdebug-mhall_2012_01_26_11_27-b00)
      OpenJDK 64-Bit Server VM (build 21.0-b17-fastdebug, mixed mode)
      jdk@ssl-jdk:~$


      ADDITIONAL OS VERSION INFORMATION :
      jdk@ssl-jdk:~$ uname -a
      Linux ssl-jdk 3.0.0-14-server #23-Ubuntu SMP Mon Nov 21 20:49:05 UTC 2011 x86_64 x86_64 x86_64 GNU/Linux
      jdk@ssl-jdk:~$ cat /etc/lsb-release
      DISTRIB_ID=Ubuntu
      DISTRIB_RELEASE=11.10
      DISTRIB_CODENAME=oneiric
      DISTRIB_DESCRIPTION="Ubuntu 11.10"
      jdk@ssl-jdk:~$


      A DESCRIPTION OF THE PROBLEM :
      If one creates a TrustManager (in this case used for creating a TLSv1.2 compliant SSL handshake testing tool using Java 7 for interoperability testing of a TLSv1.2 compliant SSL security tester), which returns null from its "getAcceptedIssuers()" method instead of the empty Certificate array seen below:

              // Create a trust manager that does not validate certificate chains
              TrustManager[] trustAllCertificates = new TrustManager[] {
                  new X509TrustManager() {
                      public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                          System.err.println("*** entering useless getAcceptedIssuers ***");
                          // XXX: cannot return null; causes an NPE because this goes into the CertificateRequest
                          return new X509Certificate[0];
                      }
                      public void checkClientTrusted(X509Certificate[] certs, String authType) {
                          System.err.println("*** entering useless checkClientTrusted ***");
                      }
                      public void checkServerTrusted(X509Certificate[] certs, String authType) {
                          System.err.println("*** entering useless checkServerTrusted ***");
                      }
                  }
              };

      Then the following uncaught exception is thrown from the JSSE implementation:

      *** entering useless getAcceptedIssuers ***
      main, handling exception: java.lang.NullPointerException
      %% Invalidated: [Session-1, SSL_RSA_WITH_NULL_SHA]
      main, SEND TLSv1.2 ALERT: fatal, description = internal_error
      main, WRITE: TLSv1.2 Alert, length = 2
      [Raw write]: length = 7
      0000: 15 03 03 00 02 02 50 ......P
      main, called closeSocket()
      javax.net.ssl.SSLException: java.lang.NullPointerException
              at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
              at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1836)
              at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1794)
              at sun.security.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1777)
              at sun.security.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1703)
              at sun.security.ssl.AppInputStream.read(AppInputStream.java:113)
              at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283)
              at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325)
              at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)
              at java.io.InputStreamReader.read(InputStreamReader.java:184)
              at java.io.BufferedReader.fill(BufferedReader.java:154)
              at java.io.BufferedReader.readLine(BufferedReader.java:317)
              at java.io.BufferedReader.readLine(BufferedReader.java:382)
              at com.mudynamics.security.ssl.SslServer.main(SslServer.java:60)
      Caused by: java.lang.NullPointerException
              at sun.security.ssl.HandshakeMessage$CertificateRequest.<init>(HandshakeMessage.java:1269)
              at sun.security.ssl.ServerHandshaker.clientHello(ServerHandshaker.java:839)
              at sun.security.ssl.ServerHandshaker.processMessage(ServerHandshaker.java:167)
              at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868)
              at sun.security.ssl.Handshaker.process_record(Handshaker.java:804)
              at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:966)
              at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1262)
              at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:816)
              at sun.security.ssl.AppInputStream.read(AppInputStream.java:102)
              ... 8 more

      This happens because the CertificateRequest message is assuming that the value returned from the TrustManager is always defined. Something should be checking the validity of values returned from the TrustManager before putting them into Handshake messages.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the attached Java Class with the following command line options:

      -Djavax.net.debug=all
      -Djavax.net.ssl.keyStore=<keystore>
      -Djavax.net.ssl.keyStorePassword=<password>
      -XX:SuppressErrorAt=/stackValue.hpp:64 (needed if using fastdebug due to some assertion failure which crashes the OpenJDK)

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The Handshaker should send the client a CertificateRequest containing an empty certificate_authorities field indicating any CA is accepted.
      ACTUAL -
      The Handshaker throws an uncaught NPE which could be avoided.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      javax.net.ssl.SSLException: java.lang.NullPointerException
              at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
              at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1836)
              at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1794)
              at sun.security.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1777)
              at sun.security.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1703)
              at sun.security.ssl.AppInputStream.read(AppInputStream.java:113)
              at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283)
              at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325)
              at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)
              at java.io.InputStreamReader.read(InputStreamReader.java:184)
              at java.io.BufferedReader.fill(BufferedReader.java:154)
              at java.io.BufferedReader.readLine(BufferedReader.java:317)
              at java.io.BufferedReader.readLine(BufferedReader.java:382)
              at com.mudynamics.security.ssl.SslServer.main(SslServer.java:60)
      Caused by: java.lang.NullPointerException
              at sun.security.ssl.HandshakeMessage$CertificateRequest.<init>(HandshakeMessage.java:1269)
              at sun.security.ssl.ServerHandshaker.clientHello(ServerHandshaker.java:839)
              at sun.security.ssl.ServerHandshaker.processMessage(ServerHandshaker.java:167)
              at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868)
              at sun.security.ssl.Handshaker.process_record(Handshaker.java:804)
              at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:966)
              at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1262)
              at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:816)
              at sun.security.ssl.AppInputStream.read(AppInputStream.java:102)
              ... 8 more


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      package com.mudynamics.security.ssl;

      import java.io.BufferedReader;
      import java.io.FileInputStream;
      import java.io.InputStream;
      import java.io.InputStreamReader;
      import java.security.KeyStore;
      import java.security.SecureRandom;
      import java.security.cert.X509Certificate;

      import javax.net.ssl.HostnameVerifier;
      import javax.net.ssl.HttpsURLConnection;
      import javax.net.ssl.KeyManagerFactory;
      import javax.net.ssl.SSLContext;
      import javax.net.ssl.SSLParameters;
      import javax.net.ssl.SSLServerSocket;
      import javax.net.ssl.SSLServerSocketFactory;
      import javax.net.ssl.SSLSession;
      import javax.net.ssl.SSLSocket;
      import javax.net.ssl.TrustManager;
      import javax.net.ssl.X509TrustManager;

      public class SslServer {
          public static void main(String[] args) throws Throwable {
              String[] supportedSuites;
              
              System.setOut(System.err);
              
              SSLContext sslContext = SslServer.createSslContext();
              SSLParameters sslParameters = sslContext.getDefaultSSLParameters();
              
              sslParameters.setAlgorithmConstraints(null);
              sslParameters.setEndpointIdentificationAlgorithm(null);
              sslParameters.setWantClientAuth(true);
              sslParameters.setNeedClientAuth(true);
              
              supportedSuites = sslParameters.getCipherSuites();
              sslParameters.setCipherSuites(supportedSuites);
              
              SSLServerSocketFactory ssf = sslContext.getServerSocketFactory();
              
              SSLServerSocket serverSocket =
                  (SSLServerSocket) ssf.createServerSocket(31337);
              
              serverSocket.setWantClientAuth(true);
              serverSocket.setNeedClientAuth(true);
              
              supportedSuites = serverSocket.getSupportedCipherSuites();
              serverSocket.setEnabledCipherSuites(supportedSuites);
              
              while (true) {
                  try {
                      SSLSocket clientSocket = (SSLSocket) serverSocket.accept();
                      System.out.println("--------------------------------------------------------------------------------");
                      InputStream is = clientSocket.getInputStream();
                      InputStreamReader isr = new InputStreamReader(is);
                      BufferedReader br = new BufferedReader(isr);
                      
                      String input = null;
                      while ((input = br.readLine()) != null) {
                          System.out.println(input);
                          System.out.flush();
                      }
                  }
                  catch (Throwable t) {
                      t.printStackTrace(System.out);
                  }
              }
          }
          
          public static SSLContext createSslContext() throws Throwable {
              // Create a trust manager that does not validate certificate chains
              TrustManager[] trustAllCertificates = new TrustManager[] {
                  new X509TrustManager() {
                      public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                          System.err.println("*** entering useless getAcceptedIssuers ***");
                          // XXX: cannot return null; causes an NPE because this goes into the CertificateRequest
      // return new X509Certificate[0];
                          return null;
                      }
                      public void checkClientTrusted(X509Certificate[] certs, String authType) {
                          System.err.println("*** entering useless checkClientTrusted ***");
                      }
                      public void checkServerTrusted(X509Certificate[] certs, String authType) {
                          System.err.println("*** entering useless checkServerTrusted ***");
                      }
                  }
              };
              
              String keyStoreFile = "./etc/ssl-server.jks";
              String keyStorePassword = "ssl-server";
              
              KeyStore keyStore = KeyStore.getInstance("jks");
              keyStore.load(new FileInputStream(keyStoreFile), keyStorePassword.toCharArray());
              KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
              keyManagerFactory.init(keyStore, keyStorePassword.toCharArray());
              
              // must use TLSv1.2 or some ciphers fail to load
              SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
              sslContext.init(keyManagerFactory.getKeyManagers(), trustAllCertificates, new SecureRandom());
              
              // KeyStore trustStore = KeyStore.getInstance("jks");
              // trustStore.load(new FileInputStream(), "ebxmlrr".toCharArray());
              // TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
              // trustManagerFactory.init(trustStore);
              
              return sslContext;
          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Returning a zero length array of X509Certificate produces the expected result of a CertificateRequest with zero length to allow any Client Cert CA.

            xuelei Xuelei Fan
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: