Forum: JRuby Load and run JAR compiled against separate version of Bouncy Castle?

68b43391f0f22ab05d54a256830f3fcf?d=identicon&s=25 Zach Margolis (Guest)
on 2014-03-25 01:32
(Received via mailing list)
Hi there,

I would like to be able to load and run a JAR within a JRuby project.
The
JAR in particular is compiled and runs against Bouncy Castle 1.5, so it
is
not compatible with the version of Bouncy Castle bundled with JRuby
(1.47
in the JAR of JRuby that I have).

What is the right way to load this JAR and execute code from it?

I've created a small gist that reproduces the errors from my current
approach, loading the sample BouncyCastleClient from the JAR.

https://gist.github.com/zachmargolis/9752311

Here are a few of the errors from various approaches:

   -

   NameError: missing class or uppercase package name
   (`com.demo.BouncyCastleClient')
    -

   java.lang.SecurityException: class
   "org.bouncycastle.jcajce.provider.symmetric.IDEA$Mappings"'s signer
   information does not match signer information of other classes in the
same
   package

Thanks in advance,

Zach Margolis
147ef000d3a4fb7bd34d2fef34d55fef?d=identicon&s=25 Bruce Adams (Guest)
on 2014-03-25 01:54
(Received via mailing list)
Zach -



I fear that I don't understand your question.



You need to explicitly, in the Ruby code, pull in the 1.5 version of
Bouncy Castle before running (which may mean even loading) any code
that uses Bouncy Castle.



I'm not quite sure what your example is showing. Does



    require 'target/multiple-bouncy-castle-HEAD-SNAPSHOT-shaded.jar'



include Bouncy Castle itself? What happens if you put that "require"
before this one:



    require 'bouncy-castle-java'



Can you directly require the Bouncy Castle jar in your Ruby code and
make sure to do it early?



- Bruce



On Mon, Mar 24, 2014, at 08:31 PM, Zach Margolis wrote:

Hi there,

I would like to be able to load and run a JAR within a JRuby project.
The JAR in particular is compiled and runs against Bouncy Castle 1.5,
so it is not compatible with the version of Bouncy Castle bundled with
JRuby (1.47 in the JAR of JRuby that I have).

What is the right way to load this JAR and execute code from it?

I’ve created a small gist that reproduces the errors from my current
approach, loading the sample BouncyCastleClient from the JAR.

[1]https://gist.github.com/zachmargolis/9752311

Here are a few of the errors from various approaches:
  * NameError: missing class or uppercase package name
    (`com.demo.BouncyCastleClient’)
  * java.lang.SecurityException: class
    “org.bouncycastle.jcajce.provider.symmetric.IDEA$Mappings”‘s signer
    information does not match signer information of other classes in
    the same package

Thanks in advance,

Zach Margolis

References

1. https://gist.github.com/zachmargolis/9752311
68b43391f0f22ab05d54a256830f3fcf?d=identicon&s=25 Zach Margolis (Guest)
on 2014-03-25 02:17
(Received via mailing list)
Bruce, thanks for responding.

As far as I understand it, requiring the -shaded JAR will set up the
classpath, but not load Bouncy Castle. Since Bouncy Castle Provider is a
signed JAR, it can't be packaged as part of a shaded JAR, so instead we
have maven configured to copy it into target/lib-signed and added to the
classpath of the shaded JAR.

Your suggestion works, it makes the "bad" file run requiring the bouncy
castle JAR directly, adding require
'target/lib-signed/bcprov-jdk15on.jar'ahead of the ruby
bouncy-castle-java works.

Unfortunately applying the same order load changes in the actual project
I'm trying to use this in does not work. Is there any way to insulate
this
part of the code that depends on 1.5?

Zach Margolis
147ef000d3a4fb7bd34d2fef34d55fef?d=identicon&s=25 Bruce Adams (Guest)
on 2014-03-25 03:18
(Received via mailing list)
Zach -



I don't know. We struggled quite a bit with getting Bouncy Castle to
fit into to our mixed JRuby/Java Rails application. We felt really
fortunate when our use of Bouncy Castle was no longer needed.



One thing that was quite surprising for us (but doesn't line up with
anything you've said) is that straight-up Jruby applications have a
noticeably different Java classloader than a Warble packaged .war file
running in a Java Servlet container (such as Tomcat). In the Servlet
container setup, Warbler has moved all of the Java jars into
WEB-INF/lib and the container gets those on the Java classpath before
JRuby starts and those jars are in a parent classloader, not JRuby's
own classloader. A vanilla JRuby run doesn't bring jars onto the
classpath until they are "require"d.



- Bruce



On Mon, Mar 24, 2014, at 09:15 PM, Zach Margolis wrote:

Bruce, thanks for responding.

As far as I understand it, requiring the -shaded JAR will set up the
classpath, but not load Bouncy Castle. Since Bouncy Castle Provider is
a signed JAR, it can’t be packaged as part of a shaded JAR, so instead
we have maven configured to copy it into target/lib-signed and added to
the classpath of the shaded JAR.

Your suggestion works, it makes the “bad” file run requiring the bouncy
castle JAR directly, adding require
'target/lib-signed/bcprov-jdk15on.jar' ahead of the ruby
bouncy-castle-java works.

Unfortunately applying the same order load changes in the actual
project I’m trying to use this in does not work. Is there any way to
insulate this part of the code that depends on 1.5?

Zach Margolis



On Mon, Mar 24, 2014 at 5:48 PM, Bruce Adams <[1]bruce.adams@acm.org>
wrote:

Zach -

I fear that I don't understand your question.

You need to explicitly, in the Ruby code, pull in the 1.5 version of
Bouncy Castle before running (which may mean even loading) any code
that uses Bouncy Castle.

I'm not quite sure what your example is showing. Does

    require 'target/multiple-bouncy-castle-HEAD-SNAPSHOT-shaded.jar'

include Bouncy Castle itself? What happens if you put that "require"
before this one:

    require 'bouncy-castle-java'

Can you directly require the Bouncy Castle jar in your Ruby code and
make sure to do it early?

- Bruce

On Mon, Mar 24, 2014, at 08:31 PM, Zach Margolis wrote:

Hi there,

I would like to be able to load and run a JAR within a JRuby project.
The JAR in particular is compiled and runs against Bouncy Castle 1.5,
so it is not compatible with the version of Bouncy Castle bundled with
JRuby (1.47 in the JAR of JRuby that I have).

What is the right way to load this JAR and execute code from it?

I’ve created a small gist that reproduces the errors from my current
approach, loading the sample BouncyCastleClient from the JAR.

[2]https://gist.github.com/zachmargolis/9752311

Here are a few of the errors from various approaches:
  * NameError: missing class or uppercase package name
    (`com.demo.BouncyCastleClient’)
  * java.lang.SecurityException: class
    “org.bouncycastle.jcajce.provider.symmetric.IDEA$Mappings”‘s signer
    information does not match signer information of other classes in
    the same package

Thanks in advance,

Zach Margolis

References

1. mailto:bruce.adams@acm.org
2. https://gist.github.com/zachmargolis/9752311
Caa2df9372ffa0a9e95b2bab1e8fea34?d=identicon&s=25 Karol Bucek (Guest)
on 2014-03-25 08:08
(Received via mailing list)
Since, I kind of felt into 'BC' / OpenSSL internals lately :
https://github.com/jruby/jruby/pull/1543 (WiP)

Here's what I think is possible to be done (once the leak is avoided and
all tests are passing) in terms of BC "integration" :

1. (again) upgrade to 1.48/1.49 (and than hopefully 1.50) which failed
previously : https://github.com/jruby/jruby/issues/1238
2. if possible allow OpenSSL to work with multiple BC versions (at least
the few latest)
3. most importantly if BC provider is "globally" installed we should try
to
work with that one ...
4. some parts of OpenSSL work without BC already - in the long run maybe
more of it could work e.g. by re-packaging some of the BC classes that
do
not depend on BC's API that much ... in the PR it's done for some of
those
already to avoid BC assuming the provider is installed

Should be noted that Warbler has changed the packaging lately - not to
copy
the jars already in the jruby jar to WEB-INF/lib,
here's how a packaged .war looks like these days :
https://github.com/mmc1ntyre/bug-demo/blob/master/...

Since Bundler requires OpenSSL it might get brought up on the CP but
that
should only happen when installing not on a require 'bundler/setup' ...

Using BC 1.50 (pretty much any > 1.47) will break (parts of) OpenSSL but
if
you do not load OpenSSL it should work, check the $CLASSPATH global if
it's
failing and review parts/gems that might be doing a require 'openssl' or
https://github.com/bundler/bundler/blob/1bf9883d71...

K.
B05d3cbc64b0031a24c2887fb6ddc173?d=identicon&s=25 christian (Guest)
on 2014-03-25 11:27
(Received via mailing list)
Bruce -

we change the behaviour of warbler to NOT copy those jars by default
into
WEB-INF/lib directory to stay more in line with a vanilla jruby
execution.

Zach -

not sure if that is relevant, but as Karol pointed out jruby needs
bouncy-castle for its openssl implementation and it is kind of bounced
to
the version of BC

with jruby-9000.dev the jruby classloader separates from the underlying
parent classloader, that means the parent classloader can use another BC
version and jruby uses its version. that separation will improve with a
patch in process to NOT register BC as security provider and instead use
BC
directly (not through javax.security API) - not sure if that helps in
your
situation. but if your client code resides in parent-classloader (which
is
in a servlet containter roughly WEB-INF/lib/*) that jruby-9000.dev
helps.

there is the jruby-complete version 1.7.1 which uses a repackaged BC
internally which might be a way to go for you. (I do not know why this
was
dropped on later versions)

- christian
68b43391f0f22ab05d54a256830f3fcf?d=identicon&s=25 Zach Margolis (Guest)
on 2014-03-25 17:20
(Received via mailing list)
Karol: Thanks for pointing out that Bundler uses OpenSSL, I think that
explains some of the issues I was seeing with Bouncy 1.47 in the
$CLASSPATH. I'm not sure we can get around that easily.

Christian: I'll look into jruby-9000.dev, but given that it's not a
release
yet, I'm a little hesitant to deploy that to production.

Also for reference, in our production setup, we don't warble or build a
.war. We use Jetty + a few JARs and just plain Ruby source (
https://github.com/square/jetpack).


Thanks for the responses everybody. At this point I think shelling out
to
OpenSSL might be a more viable option that trying to load a separate
version of BouncyCastle in a reliable fashion.

Zach Margolis
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.