Details

    • Type: Bug Bug
    • Status: Resolved Resolved
    • Priority: Critical Critical
    • Resolution: Not A Bug
    • Affects Version/s: JRuby 1.7.0.pre2
    • Fix Version/s: JRuby 1.7.5
    • Component/s: OpenSSL, Ruby 1.9.3
    • Labels:
      None
    • Environment:
      jruby 1.7.0.preview2 (1.9.3p203) 2012-08-30 8e77e2b on Java HotSpot(TM) 64-Bit Server VM 1.7.0_04-b21 [darwin-x86_64]
    • Number of attachments :
      0

      Description

      gist

      # Outputs "1\n2" in MRI 1.9.3 but just "1" in JRuby 1.7-pre2
      
      require 'socket'
      require 'openssl'
      
      host = "127.0.0.1"
      port = 9988
      
      ssl_key = "-----BEGIN RSA PRIVATE KEY-----\nMIICXQIBAAKBgQCvF80yn6D+kqGwMSQHcpHUwCRt+c39Qoy99fCWdenPthfUscec\ny62Ij8+rKYCnoE9y766a5baowdDKqq3IBOZn2Ove3zfueGbHAbWehFopG2xySf0U\nPjdmWk+DRDlCeFLig6xfAnOKWo+N0MViso3dNK8gYzb6FWqlWgZgAcMpswIDAQAB\nAoGAHv/UyZivdULas4oPue3T2dnm2T239ZXZuywW21ym96pij7ql/6Gj6KClgMVJ\nTOQ6DLxYqn3vF/OwlqEfQWF0tTUYY+xNbEDE1YsbrS5/FSzbaEYYOHzRl/vMmnsf\naNgYaSjOIecin7L71Wzq0piMIxg8BLb6IVECBku9EQNzxuECQQDZsbRgg1XZGj+r\nXAu/qXTNKQ/r7k+iPN5bXON6ApBomG+4Q7VVITL3tkGzLOphRZ37Q28FrN4B4gtC\nXb9il5lDAkEAzecTSopPi2VdcME4WWmwn1rbTp/jJNt4dGZLsNfj9RejVDd32i/L\nP7wCpoPDaaVcoF2HgvCs39qatyVg6ecu0QJBALN4q+q9nDMGTuNpWU5D2EWjyrqJ\nmCF66R6NcASQxJlWwxQ4zfBHFIvgOD4Nk5VqHZqet5MIN2d6AipOu4/+x50CQHDp\njf+rd1GHBcXGf8MwnUXWCjvEnEhi/lw+mLVivsRx8QRG4rfIy9monX949Flj8DaU\n87IPj422kG9s1QeP2nECQQCkg+RUcoQm7SiM8OXuXNeHQlvQNp65geFRxzKAXxT/\n+1Mbtwnd3AXXZBekFDDpE9U3ZQjahoe7oc1oUBuw5hXL\n-----END RSA PRIVATE KEY-----\n"
      ssl_cert = "-----BEGIN CERTIFICATE-----\nMIIC/jCCAeagAwIBAgIBAjANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJVUzEO\nMAwGA1UECgwFbG9jYWwxDTALBgNVBAsMBGFlcm8xCzAJBgNVBAMMAkNBMB4XDTEy\nMDExNDAwMjcyN1oXDTEzMDExMzAwMjcyN1owSDELMAkGA1UEBhMCVVMxDjAMBgNV\nBAoMBWxvY2FsMQ0wCwYDVQQLDARhZXJvMQswCQYDVQQLDAJDQTENMAsGA1UEAwwE\ncHVtYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArxfNMp+g/pKhsDEkB3KR\n1MAkbfnN/UKMvfXwlnXpz7YX1LHHnMutiI/PqymAp6BPcu+umuW2qMHQyqqtyATm\nZ9jr3t837nhmxwG1noRaKRtsckn9FD43ZlpPg0Q5QnhS4oOsXwJzilqPjdDFYrKN\n3TSvIGM2+hVqpVoGYAHDKbMCAwEAAaOBhTCBgjAMBgNVHRMBAf8EAjAAMDEGCWCG\nSAGG+EIBDQQkFiJSdWJ5L09wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0G\nA1UdDgQWBBTyDyJlmYBDwfWdRj6lWGvoY43k9DALBgNVHQ8EBAMCBaAwEwYDVR0l\nBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQEFBQADggEBAIbBVfoVCG8RyVesPW+q\n5i0wAMbHZ1fwv1RKp17c68DYDs0YYPi0bA0ss8AgpU6thWmskxPiFaE6D5x8iv9f\nzkcHxgr1Mrbx6RLx9tLUVehSmRv3aiVO4k9Mp6vf+rJK1AYeaGBmvoqTBLwy7Jrt\nytKMdqMJj5jKWkWgEGgTnjzbcOClmCQab9isigIzTxMyC/LjeKZe8pPeVX6OM8bY\ny8XGZp9B7uwdPzqt/g25IzTC0KsQwq8cB0raAtZzIyTNv42zcUjmQNVazAozCTcq\nMsEtK2z7TYBC3udTsdyS2qVqCpsk7IMOBGrw8vk4SNhO+coiDObW2K/HNvhl0tZC\noQI=\n-----END CERTIFICATE-----"
      
      ctx = OpenSSL::SSL::SSLContext.new
      ctx.key = OpenSSL::PKey::RSA.new ssl_key
      ctx.cert = OpenSSL::X509::Certificate.new ssl_cert
      ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
      
      tcp_server = TCPServer.new(host, port)
      @server = OpenSSL::SSL::SSLServer.new(tcp_server, ctx)
      
      t = Thread.new do
        ios = IO.select [@server]
        ios.first.each do |sock|
          c = sock.accept
          loop do
            ready = IO.select [c]
            ready.first.each do |c|
              data = c.read(1) # read and readpartial are both broken for this test case
              puts data
            end
          end
        end
      end
      
      client = TCPSocket.new host, port
      sslclient = OpenSSL::SSL::SSLSocket.new(client)
      sslclient.connect
      sslclient.write "1"
      sslclient.write "2"
      
      t.join
      

        Activity

        Hide
        Charles Oliver Nutter added a comment -

        I have been experimenting with this today, and I've come to the determination that the easiest way to fix buffering.rb would be to not use it at all.

        Here's a patch that at least starts to remove the extra buffering logic from reads: https://gist.github.com/headius/6477733

        With this patch and a modified version of my earlier one, the test script again runs to completion. However, I don't have the logic quite right since there's multiple failures in SSLSocket tests.

        I have also filed http://bugs.ruby-lang.org/issues/8875 with MRI for this issue.

        Note also that using sysread instead of read makes the original script work (with my earlier patch) without modifying buffering.rb, since it only utilizes SSLSocket's internal buffers in that case.

        So to summarize once again... there are two problems:

        • SSLSocket has its own internal buffers that IO.select must be patched to see.
        • read* methods on SSLSocket are provided by openssl/buffering.rb, which has an additional buffer IO.select can't see.
        Show
        Charles Oliver Nutter added a comment - I have been experimenting with this today, and I've come to the determination that the easiest way to fix buffering.rb would be to not use it at all. Here's a patch that at least starts to remove the extra buffering logic from reads: https://gist.github.com/headius/6477733 With this patch and a modified version of my earlier one, the test script again runs to completion. However, I don't have the logic quite right since there's multiple failures in SSLSocket tests. I have also filed http://bugs.ruby-lang.org/issues/8875 with MRI for this issue. Note also that using sysread instead of read makes the original script work (with my earlier patch) without modifying buffering.rb, since it only utilizes SSLSocket's internal buffers in that case. So to summarize once again... there are two problems: SSLSocket has its own internal buffers that IO.select must be patched to see. read* methods on SSLSocket are provided by openssl/buffering.rb, which has an additional buffer IO.select can't see.
        Hide
        codecraig added a comment -

        Charles, thanks (again). I suppose we'll keep deploying WARs with Tomcat for now (we utilize mutual authentication (or 2-way SSL).

        Show
        codecraig added a comment - Charles, thanks (again). I suppose we'll keep deploying WARs with Tomcat for now (we utilize mutual authentication (or 2-way SSL).
        Hide
        Charles Oliver Nutter added a comment -

        I'm going to call this Not A Bug because it's a flaw in the way SSLSocket works in MRI (and maybe in general).

        There may be things we can do to improve it but the specific case described here is an issue in all implementations that share OpenSSL::SSLSocket and its buffering.rb.

        It would be really helpful if someone could figure out what the actual issue is with Puma, or help us implement Evan's minissl for JRuby (his preferred path forward).

        Show
        Charles Oliver Nutter added a comment - I'm going to call this Not A Bug because it's a flaw in the way SSLSocket works in MRI (and maybe in general). There may be things we can do to improve it but the specific case described here is an issue in all implementations that share OpenSSL::SSLSocket and its buffering.rb. It would be really helpful if someone could figure out what the actual issue is with Puma, or help us implement Evan's minissl for JRuby (his preferred path forward).
        Hide
        Ben Porterfield added a comment - - edited

        I'm not sure if this is what you mean by actual, but I got to this bug report by starting with Puma and slowly removing code that was not causing the error. Things may have changed since then, but if I recall correctly, there are essentially two selects with a read. Here is the first:

        https://github.com/puma/puma/blob/master/lib/puma/server.rb#L284

        And, once you whittle down the code, here is the second:

        https://github.com/puma/puma/blob/master/lib/puma/reactor.rb#L25

        With the next read (that breaks in this test case):

        https://github.com/puma/puma/blob/master/lib/puma/reactor.rb#L31

        It appears to me that the test case written here is what is actually happening with Puma.

        Show
        Ben Porterfield added a comment - - edited I'm not sure if this is what you mean by actual, but I got to this bug report by starting with Puma and slowly removing code that was not causing the error. Things may have changed since then, but if I recall correctly, there are essentially two selects with a read. Here is the first: https://github.com/puma/puma/blob/master/lib/puma/server.rb#L284 And, once you whittle down the code, here is the second: https://github.com/puma/puma/blob/master/lib/puma/reactor.rb#L25 With the next read (that breaks in this test case): https://github.com/puma/puma/blob/master/lib/puma/reactor.rb#L31 It appears to me that the test case written here is what is actually happening with Puma.
        Hide
        Ben Porterfield added a comment -

        Oh, I see - Puma is not using SSLSocket. Duh.

        I'll take a look at the existing (unfinished) Java version of MiniSSL and see if it's something I might be able to tackle.

        Show
        Ben Porterfield added a comment - Oh, I see - Puma is not using SSLSocket. Duh. I'll take a look at the existing (unfinished) Java version of MiniSSL and see if it's something I might be able to tackle.

          People

          • Assignee:
            Charles Oliver Nutter
            Reporter:
            Ben Porterfield
          • Votes:
            1 Vote for this issue
            Watchers:
            6 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: