We’re having problems reading a PEM file with jruby-1.7.10, that was
able
to be read successfully in jruby-1.7.9.
A colleague of mine is trying to write up a test case to send (which
doesn’t use the actual PEM file we’re failing on, since that has a
confidential key), but I thought I’d see if anyone else had encountered
this error and determined a solution:
#<OpenSSL::PKey::RSAError: Neither PUB key nor PRIV key:>
[“org/jruby/ext/openssl/PKeyRSA.java:289:in `initialize’”,
…
Here’s the result of the investigation so far:
We can read the file in MRI, jruby-1.7.9 and earlier jruby (back to
1.7.4)
We can’t read it with 1.7.10, 1.7.11-SNAPSHOT and 9000.dev.
If we include bcprov-jdk15on-1.49.jar and bcpkix-jdk15on-1.49.jar in
the
class path before the jruby jars (which look like 1.47), the file can be
read with 1.7.10 and 1.7.11-SNAPSHOT, but still not with 9000.dev.
If we include bcprov-jdk15on-1.50.jar and bcpkix-jdk15on-1.50.jar in
the
class path, things go haywire.
For our purposes, we’ll probably revert to 1.7.9, but I’m happy to test
out
any potential fixes if that would help.
If we include bcprov-jdk15on-1.49.jar and bcpkix-jdk15on-1.49.jar in the
class path before the jruby jars (which look like 1.47), the file can be
read with 1.7.10 and 1.7.11-SNAPSHOT, but still not with 9000.dev.
with 9000.dev you need to require the bc*jar for the ruby part to see
If we include bcprov-jdk15on-1.50.jar and bcpkix-jdk15on-1.50.jar in
the
class path, things go haywire.
look like the BC API changed a bit here
For our purposes, we’ll probably revert to 1.7.9, but I’m happy to test
out
It does seem to work with 1.47 on the classpath also. I had prematurely
concluded that it was a version issue with bouncy-castle, because
including
the bouncy-castle-java gem did not seem to fix the problem, but those
1.47
jars do fix it.
We’re trying on Mac OS X, Linux (Ubuntu 12.04) and Windows Server 2012.
I guess it now feels like the issue may be around the inclusion of the
bc
jars from that gem into the classpath.
Any ideas? Do we need to adopt the same approach as you’ve suggested for
9000.dev (ie an explicit require)? That latter is a pain, because all
our
systems are made to be deployed to either MRI or jruby, so we try to
avoid
any java specific code.
In development & test, we use jruby-complete.jar, which is how I’m
running
the tests that expose the problem. We also have the exact same
applications
running under both jruby and MRI.
In production, we deploy the applications as web applications (built
with
warbler) and as stand-alone executables (using runnable war files).
We send our clients war files to run, and those run on application
servers
running other applications. Everything we need on the target machine has
to
be packaged in the war. That’s why it’s not very workable to have to set
a
class path on deployment.
actually the bouncy-castle jars are part of jruby (either
jruby-complete.jar, jruby-jars.gem or the distribution tarball) and we
see
this problem of not loading those jars on various issues but still
unclear
why. since I can no reproduce the problem so far (not tried the last
hint I
got) it would great if you could try out the latest idea to fix it:
so basically not using a glob to find the bouncy castle jars.
We’ve come up with a pretty minimal example that shows the change in
behaviour from jruby 1.7.9 and 1.7.10. We’re using the jruby-complete
jars
unaltered from jruby.org/download
First, create a dummy key and certificate. Use password “TestPW” when
prompted:
it is already bedtime for me - but yes I made the same observation that
the
jar from within the jruby jar get preference which is a problem when you
install a gem and want to use jars from the gem instead.
actually if I look at all three 1.7.9, 1.7.10 and 9000.dev they all look
wrong to me, I would expect them to be:
file:/Volumes/Code/testbc/testgem/gems/bouncy-castle-java-1.5.0147/lib/bcpkix-jdk15on-147.jar
file:/Volumes/Code/testbc/testgem/gems/bouncy-castle-java-1.5.0147/lib/bcprov-jdk15on-147.jar
the jar within a jar in general works BUT there be cases where is does
not.
that is why I unpack the jruby-stdlib.jar for the war-file in my
personal
project:
I also added a testcase to jruby itself which verifies that the
jopenssl.jar gets loaded (to late to find serach for commits now).
what I found with getting websphere to work with a simple rails app that
a
gem ‘jruby-openssl’
gem ‘bouncy-castle-java’
helped to find those jars from the gems (websphere can not load those
embedded jars at all).
unfortunately I was still not able to reproduce your failing PEM. but
the
default gems should be just gems and not given preference IMO. I will
double-check what the other jruby folks think, about that.
thanx for digging further.
regards,
christian
PS did not know about the $CLASSPATH varibale - nice to have
I’ve been some more digging, and it looks like the issue is that since
jruby-1.7.10, if we require a gem that is already contained in the
jruby-complete jar as well as outside it, it will prefer to use the
internal one. That looks to be a problem when the gem contains a jar,
because then it puts a jar inside a jar in the classpath.
Here’s some small example code (I’ve called the script
test_classpath.rb):
So I guess this comes down to the question of whether we are using a
classloader in jruby that can load classes from a jar inside a jar, Or
is
this just a red herring?
OK my last email was not really helpful - wasn’t my day.
loading jars from within jruby-complete.jar works even for you since you
get some errors from within the jopenssl.jar (when I understood one of
the
many remarks right).
the problem with this piece of code is that the actual error gets
interpreted as “it can not load the PEM” which makes debugging really
hard.
for this extracted the piece of code of jopenssl.jar into that
rsa_from_file.rb script:
require ‘openssl’
file_name = ‘mykey.pem’
pwd = ‘TestPW’
begin
x = OpenSSL::PKey::RSA.new(File.read(file_name), pwd)
puts x.inspect
p x.class
rescue Exception => e
puts “e.message = #{e.message}”
puts “obj = " + e.backtrace.join(”\n")
end
begin
p
org.jruby.ext.openssl.x509store.PEMInputOutput.readPrivateKey(java.io.StringReader.new(File.read(file_name).to_java()),
pwd.to_java.to_char_array)
rescue => e
puts “e.message = #{e.message}”
puts “obj = " + e.backtrace.join(”\n")
end
that PEMInputOutput.readPrivateKey is the one which reads the PEM file
correctly on my machine and I assume that method has a problem on your
machine. maybe the stacktrace helps to see the problem.
I also made an issue on github to clearify the loading of gems, default
gems, etc
Thanks for following up on that - was trying some other things myself,
and
found the explicitly requiring the bouncy castle jar files using an
absolute path, before requiring openssl got things to work, but it’s not
a
very satisfying work-around.
Here’s the result of that script (I explicitly added the gems at the top
to
get it to still work with 1.7.9, so the line number will be off a bit
from
your script, but the error messages don’t change):