Uploaded image for project: 'Confluence Data Center'
  1. Confluence Data Center
  2. CONFSERVER-2848

Unregistered SSL certificates can cause http requests to hang indefinitely

    • Icon: Bug Bug
    • Resolution: Won't Fix
    • Icon: Medium Medium
    • None
    • 1.3.5
    • None

      Sulka notes:

      If you use the

      {rss}

      or

      {jiraissues}

      macro to access another server using SSL (https), and the remote server has an SSL certificate that is not registered with Confluence's JVM, the web request will hang indefinitely, eventually exhausting all the Confluence server threads.

      We need to have some way to prevent this from occurring - it might be pretty deep inside the JDK though.

            [CONFSERVER-2848] Unregistered SSL certificates can cause http requests to hang indefinitely

            Hi, Sulka

            Sorry it's been so long on this one, but I've found a few interesting things.

            Looking at your stack trace, Java isn't hanging on the certificate itself (I tried this locally, and if the certificate doesn't have a trusted signature, it's just rejected with an exception). What's happening is that one thread is holding on to a lock on the SSLSocketFactory, and all the other threads are waiting for it to release this lock. The connection hasn't even made a request yet - it's just generating the socket:

            at java.lang.reflect.Constructor.newInstance(Constructor.java:274)
            at java.lang.Class.newInstance0(Class.java:308)
            at java.lang.Class.newInstance(Class.java:261)
            at javax.net.ssl.SSLSocketFactory.getDefault(DashoA6275)

            • locked <0x75ce7b70> (a java.lang.Class)
              at org.apache.commons.httpclient.protocol.SSLProtocolSocketFactory.createSocket(SSLProtocolSocketFactory.java:93)
              at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:652)

            Looking further up the trace, the socket seems to be frozen trying to initialise some kind of random number using SecureRandom:

            at sun.security.provider.SecureRandom.engineNextBytes(SecureRandom.java:169)

            • locked <0x4a8862b8> (a sun.security.provider.SecureRandom)
              at java.security.SecureRandom.nextBytes(SecureRandom.java:381)
            • locked <0x4a8862f8> (a java.security.SecureRandom)
              at java.security.SecureRandom.next(SecureRandom.java:403)
              at java.util.Random.nextInt(Random.java:191)
              at com.sun.net.ssl.internal.ssl.SSLContextImpl.engineInit(DashoA6275)

            And looking at the top of the trace, it's frozen reading some kind of FileInputStream:

            "TP-Processor7" daemon prio=1 tid=0x089a8df0 nid=0x3dc1 runnable [7c385000..7c38887c]
            at java.io.FileInputStream.readBytes(Native Method)
            at java.io.FileInputStream.read(FileInputStream.java:194)
            at java.io.BufferedInputStream.read1(BufferedInputStream.java:220)
            at java.io.BufferedInputStream.read(BufferedInputStream.java:277)

            • locked <0x4a886238> (a java.io.BufferedInputStream)
              at java.io.BufferedInputStream.fill(BufferedInputStream.java:183)
              at java.io.BufferedInputStream.read1(BufferedInputStream.java:222)
              at java.io.BufferedInputStream.read(BufferedInputStream.java:277)
            • locked <0x4a886258> (a java.io.BufferedInputStream)
              at sun.security.provider.SeedGenerator$URLSeedGenerator.getSeedByte(SeedGenerator.java:467)

            What seems to be happening is that the SSL Socket factory is going to the Operating System for a source of secure random numbers, and the OS either isn't delivering them, or isn't delivering them fast enough.

            On Linux, Java uses /dev/random by default to generate secure random numbers. From the /dev/random man page:

                   When read, the /dev/random device will only return random bytes within
                   the estimated number of bits of noise in the entropy pool. ... When the
                   entropy pool is empty, reads from /dev/random will block until additional
                   environmental noise is gathered.

            /dev/random runs out of entropy pretty quickly if you don't have specialised crypto hardware - just do a 'cat /dev/random' and see how quickly it stops producing data. However, you can switch Java to using /dev/urandom (which doesn't block, it just degrades to using less secure random numbers) by changing a property in your java.security file: (according to http://forum.java.sun.com/thread.jspa?threadID=230198&messageID=820456)

                  The problem seemed to be that the security provider used /dev/random as an entropy generator,
                  and it somehow wasn't working. By editing the $JAVA_HOME/jre/lib/security/java.security file and
                  changing the property:

                   securerandom.source=file:/dev/random

                   to:

                   securerandom.source=file:/dev/urandom

            This should catch the crashing problem.

            On to actually being able to retrieve the RSS feed from the HTTPS server.

            You have to register the CA certificate used to sign the server certificate with Java. This is done at the JDK/JSSE level. Java stores its trusted CA certificates in $JAVA_HOME/lib/security/cacert - providing you can export the root CA certificate from your webserver, you should be able to add another trusted certificate to that file using keytool:

            keytool -import -trustcacerts -keystore $JAVA_HOME/jre/lib/security/cacerts -file mycertificate.cer -alias bogusinternalcertificate

            Charles Miller (Inactive) added a comment - Hi, Sulka Sorry it's been so long on this one, but I've found a few interesting things. Looking at your stack trace, Java isn't hanging on the certificate itself (I tried this locally, and if the certificate doesn't have a trusted signature, it's just rejected with an exception). What's happening is that one thread is holding on to a lock on the SSLSocketFactory, and all the other threads are waiting for it to release this lock. The connection hasn't even made a request yet - it's just generating the socket: at java.lang.reflect.Constructor.newInstance(Constructor.java:274) at java.lang.Class.newInstance0(Class.java:308) at java.lang.Class.newInstance(Class.java:261) at javax.net.ssl.SSLSocketFactory.getDefault(DashoA6275) locked <0x75ce7b70> (a java.lang.Class) at org.apache.commons.httpclient.protocol.SSLProtocolSocketFactory.createSocket(SSLProtocolSocketFactory.java:93) at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:652) Looking further up the trace, the socket seems to be frozen trying to initialise some kind of random number using SecureRandom: at sun.security.provider.SecureRandom.engineNextBytes(SecureRandom.java:169) locked <0x4a8862b8> (a sun.security.provider.SecureRandom) at java.security.SecureRandom.nextBytes(SecureRandom.java:381) locked <0x4a8862f8> (a java.security.SecureRandom) at java.security.SecureRandom.next(SecureRandom.java:403) at java.util.Random.nextInt(Random.java:191) at com.sun.net.ssl.internal.ssl.SSLContextImpl.engineInit(DashoA6275) And looking at the top of the trace, it's frozen reading some kind of FileInputStream: "TP-Processor7" daemon prio=1 tid=0x089a8df0 nid=0x3dc1 runnable [7c385000..7c38887c] at java.io.FileInputStream.readBytes(Native Method) at java.io.FileInputStream.read(FileInputStream.java:194) at java.io.BufferedInputStream.read1(BufferedInputStream.java:220) at java.io.BufferedInputStream.read(BufferedInputStream.java:277) locked <0x4a886238> (a java.io.BufferedInputStream) at java.io.BufferedInputStream.fill(BufferedInputStream.java:183) at java.io.BufferedInputStream.read1(BufferedInputStream.java:222) at java.io.BufferedInputStream.read(BufferedInputStream.java:277) locked <0x4a886258> (a java.io.BufferedInputStream) at sun.security.provider.SeedGenerator$URLSeedGenerator.getSeedByte(SeedGenerator.java:467) What seems to be happening is that the SSL Socket factory is going to the Operating System for a source of secure random numbers, and the OS either isn't delivering them, or isn't delivering them fast enough. On Linux, Java uses /dev/random by default to generate secure random numbers. From the /dev/random man page:        When read, the /dev/random device will only return random bytes within        the estimated number of bits of noise in the entropy pool. ... When the        entropy pool is empty, reads from /dev/random will block until additional        environmental noise is gathered. /dev/random runs out of entropy pretty quickly if you don't have specialised crypto hardware - just do a 'cat /dev/random' and see how quickly it stops producing data. However, you can switch Java to using /dev/urandom (which doesn't block, it just degrades to using less secure random numbers) by changing a property in your java.security file: (according to http://forum.java.sun.com/thread.jspa?threadID=230198&messageID=820456 )       The problem seemed to be that the security provider used /dev/random as an entropy generator,       and it somehow wasn't working. By editing the $JAVA_HOME/jre/lib/security/java.security file and       changing the property:        securerandom.source= file:/dev/random        to:        securerandom.source= file:/dev/urandom This should catch the crashing problem. On to actually being able to retrieve the RSS feed from the HTTPS server. You have to register the CA certificate used to sign the server certificate with Java. This is done at the JDK/JSSE level. Java stores its trusted CA certificates in $JAVA_HOME/lib/security/cacert - providing you can export the root CA certificate from your webserver, you should be able to add another trusted certificate to that file using keytool: keytool -import -trustcacerts -keystore $JAVA_HOME/jre/lib/security/cacerts -file mycertificate.cer -alias bogusinternalcertificate

            Surely this is a JVM bug? I can't believe that the JVM would just "hang" entirely if this occurs?

            Aren't we using HttpClient for these requests anyway? Doesn't that provide timeout facilities? Is it a bug in HttpClient?

            m

            Mike Cannon-Brookes added a comment - Surely this is a JVM bug? I can't believe that the JVM would just "hang" entirely if this occurs? Aren't we using HttpClient for these requests anyway? Doesn't that provide timeout facilities? Is it a bug in HttpClient? m

            I think you could fix this by implementing a new TrustManager and then installing it into the JVM

            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, myTrustManager, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

            Of course the implementation is non-trivial if you do anything but silently accept all certificates.

            Sulka Haro added a comment - I think you could fix this by implementing a new TrustManager and then installing it into the JVM SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, myTrustManager, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); Of course the implementation is non-trivial if you do anything but silently accept all certificates.

              Unassigned Unassigned
              cmiller@atlassian.com Charles Miller (Inactive)
              Affected customers:
              1 This affects my team
              Watchers:
              0 Start watching this issue

                Created:
                Updated:
                Resolved: