hierynomus/sshj

OSGI dependencies are broken

15knots opened this issue · 28 comments

The manifest header declares a dependency to package net.i2p.crypto.eddsa.math, but bundle net.i2p.crypto.eddsa does not export that package. (The pom of net.i2p.crypto.eddsa explicitly excludes the package from the exported package list.)

This results in a tycho error when building:
Missing requirement: com.hierynomus.sshj 0.17.2 requires 'package net.i2p.crypto.eddsa.math 0.0.0' but it could not be found

As I'm not an OSGI whiz, what would be the best solution for this? Isn't this something that needs to be fixed in the net.i2p.crypto.eddsa pom?

src/main/java/net/schmizz/sshj/common/KeyType.java imports the package and uses types from it.

So it needs to be fixed in the net.i2p.crypto.eddsa pom.

Thank you for the quick response!

Please publish a new release containing this fix. Thank You!

Done, version 0.18.0 is downloadable from Maven.

Unfortunately it's still broken. The build.gradle file also needs to be corrected. I've created a pull request.

I am currently working on a project that tests how sshj behaves in an OSGI environment.
Things I found so far:

  1. Missing requirement: com.hierynomus.sshj 0.19.0 requires 'package net.i2p.crypto.eddsa.math 0.0.0' but it could not be found. This is because sshj imports package net.i2p.crypto.eddsa.math, which is not exported (possibly a bug in gradle bundler which adds the import?)

  2. ClassNotFoundEx: org.bouncycastle.jce.provider.BouncyCastleProvider in net.schmizz.sshj.common.SecurityUtils.BouncyCastleRegistration.run() due to a missing dependency in manifest.mf.

  3. Shouldn´ t sshj export packages com.hierynomus.sshj.*, too?

I fixed all of the above by changing build.gradlethis way:

jar {
    manifest {
      // please see http://bnd.bndtools.org/chapters/390-wrapping.html
        instruction "Bundle-Description", "SSHv2 library for Java"
        instruction "Bundle-License", "http://www.apache.org/licenses/LICENSE-2.0.txt"
        instruction "Import-Package", \
          "com.jcraft.jzlib*;version=\"[1.1,2)\";resolution:=optional", \
          "!com.hierynomus.sshj.*", "!net.schmizz.*", \
          "!net.i2p.crypto.eddsa.math", \
          "*"
        instruction "Require-Bundle", \
          "bcprov;bundle-version=\"$bouncycastleVersion\";resolution:=optional", \
          "bcprov;bundle-version=\"$bouncycastleVersion\";resolution:=optional"
        instruction "Export-Package", "com.hierynomus.sshj.*", "net.schmizz.*"
  }
}

But I am still working on my testing project...

Let me know once you've finished testing. I'll reopen this ticket until then.

Test project is here: https://github.com/15knots/sshj.osgi.tests
Currently, it only tests the missing-requirement issue above.

I changed the testing project to work with development versions of sshj, too. It now proves that the missing requirements issue is solved in sshj now.

@15knots is there any specific reason why you are using Require-Bundle? It's use is generally discouraged. see http://stackoverflow.com/questions/1865819/when-should-i-use-import-package-and-when-should-i-use-require-bundle for an example

@adagios Thanks, I was wondering the same, but having not enough experience with OSGI bundles I accepted the change. If you have a better proposition I'm all ears.

@hierynomus I think I got it running with only Import-Package, but I would just like to check that when it doesn't find the following cyphers that it's not related to bouncy castle:

net.schmizz.sshj.DefaultConfig : aes192-ctr:Illegal key size
net.schmizz.sshj.DefaultConfig : aes256-ctr:Illegal key size
net.schmizz.sshj.DefaultConfig : aes192-cbc:Illegal key size
net.schmizz.sshj.DefaultConfig : aes256-cbc:Illegal key size
net.schmizz.sshj.DefaultConfig : blowfish-ctr:Illegal key size
net.schmizz.sshj.DefaultConfig : serpent192-cbc:Illegal key size
net.schmizz.sshj.DefaultConfig : serpent192-ctr:Illegal key size
net.schmizz.sshj.DefaultConfig : serpent256-cbc:Illegal key size
net.schmizz.sshj.DefaultConfig : serpent256-ctr:Illegal key size
net.schmizz.sshj.DefaultConfig : twofish192-cbc:Illegal key size
net.schmizz.sshj.DefaultConfig : twofish192-ctr:Illegal key size
net.schmizz.sshj.DefaultConfig : twofish256-cbc:Illegal key size
net.schmizz.sshj.DefaultConfig : twofish256-ctr:Illegal key size
net.schmizz.sshj.DefaultConfig : twofish-cbc:Illegal key size
net.schmizz.sshj.DefaultConfig : arcfour256:Illegal key size or default parameters

Nope, that is related to not running a JVM with the unlimited crypto extensions :)

I've created a pull request with my solution.

@15knots wan't to test it?

With regards to exporting com.hierynomus.sshj packages, is it something that clients should use directly? I looked and they seemed like internal classes, so I left them out of the Export-Package.

@adagios, @hierynomus: I used Require-Bundle", "bcprov because I had difficulties to figure out which packages should be imported: I just wanted to be on the safe side,

With d1dff55, test no longer fail.
mvn -Dsshj.version=0.19.2-dev.6.uncommitted+d1dff55 verify runs successfully.

Thanks!

@hierynomus Pls help me to check out the commit of the PR for #295.
Will try then.

@15knots Just pull the repository and check out 66d4b34

Sorry for the delay, github``s web UI confused me first, then I realized that I have to switch to adagios´ repo to get that commit:-)

Commit 66d4b34 for #295 fails as follows:
mvn -Dsshj.version=0.19.2-dev.8.uncommitted+66d4b34 verify
...

testBouncyCastleProvider(net.schmizz.sshj.common.SecurityUtilsTest)  Time elapsed: 0.005 sec  <<< ERROR!
net.schmizz.sshj.common.SSHRuntimeException: Failed to register BouncyCastle as the defaut JCE provider
        at net.schmizz.sshj.common.SecurityUtils.register(SecurityUtils.java:254)
        at net.schmizz.sshj.common.SecurityUtils.isBouncyCastleRegistered(SecurityUtils.java:227)
        at net.schmizz.sshj.common.SecurityUtilsTest.testBouncyCastleProvider(SecurityUtilsTest.java:27)

Results :

Tests in error:
  SecurityUtilsTest.testBouncyCastleProvider:27 » SSHRuntime Failed to register

Unfortunately, SecurityUtils.registerSecurityProvider()swallows the original exception, it is just logged at INFO level, so no more diags ATM.

I had a look, and It's failing because it can't find the class org.bouncycastle.jce.provider.BouncyCastleProvider but it's because the bouncycastle bundles are not included in the test run.

I took a look at the equinox config at target\work\configuration\config.ini and it only lists the sshj and the eddsa bundles.
But, I don't really know how tycho works and was unable to add bouncycastle to the list of bundles.

@adagios You are right!
The bouncycastle bundles are added to the tests runtime only if they are referenced by a Require-Bundle` in some manifest.mf file.
I fixed my testing project, commit 66d4b34 for #295 succeeds now.

@hierynomus I think that this is done. Can you share when are you thinking of releasing a new version? I would really like to switch to an official version :)

I'll merge #295 in in a moment. It might be cool if we could somehow integrate the osgi test into the build so that it is verified to not break. Don't know how feasible that is, and whether there are plugins for that for Gradle?

#295 has been merged.

I'm encountering the same error now at runtime in OSGi. Ed25519PublicKey does a spec.getParams().getCurve().equals(ed25519.getCurve()) at [1] which requires visibility to net.i2p.crypto.eddsa.math which is neither exported from net.i2p.crypto.eddsa nor (per original message in this issue) imported here. Of course it can't be imported here but even using it without an import can cause NoClassDefFound.

It might be possible to avoid the problem here using !Objects.equal(spec.getParams().getCurve(), ed25519.getCurve()) at [1] instead.

(The right fix I think per the second and third messages would be in net.i2p.crypto.eddsa either to export the math package or remove it from the API of exported classes.)

A workaround -- in case someone else comes across this -- is to wrap the dependencies to explicitly export and import math; it's ugly but it works:

        <bundle dependency="true">wrap:mvn:net.i2p.crypto/eddsa/${eddsa.version}$overwrite=merge&amp;Bundle-SymbolicName=net.i2p.crypto.eddsa_wrapped&amp;Bundle-Version=${eddsa.version}&amp;Export-Package=*;version="${eddsa.version}"</bundle>
        <bundle dependency="true">wrap:mvn:com.hierynomus/sshj/${sshj.version}$overwrite=merge&amp;Bundle-SymbolicName=com.hierynomus.sshj_wrapped&amp;Bundle-Version=${sshj.version}&amp;Import-Package=net.i2p.crypto.eddsa.math;version="[0.2,1)",javax.crypto,javax.crypto.interfaces,javax.crypto.spec,net.i2p.crypto.eddsa;version="[0.2,1)",net.i2p.crypto.eddsa.spec;version="[0.2,1)",com.jcraft.jzlib;version="[1.1,2)";resolution:=optional,org.slf4j;version="[1.7,5)",org.bouncycastle.asn1;resolution:=optional;version="[1.60,2)",org.bouncycastle.asn1.nist;resolution:=optional;version="[1.60,2)",org.bouncycastle.asn1.x9;resolution:=optional;version="[1.60,2)",org.bouncycastle.crypto.ec;resolution:=optional;version="[1.60,2)",org.bouncycastle.crypto.prng;resolution:=optional;version="[1.60,2)",org.bouncycastle.jce.spec;resolution:=optional;version="[1.60,2)",org.bouncycastle.math.ec;resolution:=optional;version="[1.60,2)",org.bouncycastle.openssl;resolution:=optional;version="[1.60,2)",org.bouncycastle.openssl.jcajce;resolution:=optional;version="[1.60,2)",org.bouncycastle.util.encoders;resolution:=optional;version="[1.60,2)",javax.net,javax.security.auth,javax.security.auth.login,org.ietf.jgss,org.bouncycastle.jce.provider;resolution:=optional;version="[1.60,2)"</bundle>

[1] https://github.com/hierynomus/sshj/blob/master/src/main/java/com/hierynomus/sshj/signature/Ed25519PublicKey.java#L37

I'm encountering the same error now at runtime in OSGi. Ed25519PublicKey does a spec.getParams().getCurve().equals(ed25519.getCurve()) at [1] which requires visibility to net.i2p.crypto.eddsa.math which is neither exported from net.i2p.crypto.eddsa nor (per original message in this issue) imported here. Of course it can't be imported here but even using it without an import can cause NoClassDefFound.

It might be possible to avoid the problem here using !Objects.equal(spec.getParams().getCurve(), ed25519.getCurve()) at [1] instead.

(The right fix I think per the second and third messages would be in net.i2p.crypto.eddsa either to export the math package or remove it from the API of exported classes.)

A workaround -- in case someone else comes across this -- is to wrap the dependencies to explicitly export and import math; it's ugly but it works:

        <bundle dependency="true">wrap:mvn:net.i2p.crypto/eddsa/${eddsa.version}$overwrite=merge&amp;Bundle-SymbolicName=net.i2p.crypto.eddsa_wrapped&amp;Bundle-Version=${eddsa.version}&amp;Export-Package=*;version="${eddsa.version}"</bundle>
        <bundle dependency="true">wrap:mvn:com.hierynomus/sshj/${sshj.version}$overwrite=merge&amp;Bundle-SymbolicName=com.hierynomus.sshj_wrapped&amp;Bundle-Version=${sshj.version}&amp;Import-Package=net.i2p.crypto.eddsa.math;version="[0.2,1)",javax.crypto,javax.crypto.interfaces,javax.crypto.spec,net.i2p.crypto.eddsa;version="[0.2,1)",net.i2p.crypto.eddsa.spec;version="[0.2,1)",com.jcraft.jzlib;version="[1.1,2)";resolution:=optional,org.slf4j;version="[1.7,5)",org.bouncycastle.asn1;resolution:=optional;version="[1.60,2)",org.bouncycastle.asn1.nist;resolution:=optional;version="[1.60,2)",org.bouncycastle.asn1.x9;resolution:=optional;version="[1.60,2)",org.bouncycastle.crypto.ec;resolution:=optional;version="[1.60,2)",org.bouncycastle.crypto.prng;resolution:=optional;version="[1.60,2)",org.bouncycastle.jce.spec;resolution:=optional;version="[1.60,2)",org.bouncycastle.math.ec;resolution:=optional;version="[1.60,2)",org.bouncycastle.openssl;resolution:=optional;version="[1.60,2)",org.bouncycastle.openssl.jcajce;resolution:=optional;version="[1.60,2)",org.bouncycastle.util.encoders;resolution:=optional;version="[1.60,2)",javax.net,javax.security.auth,javax.security.auth.login,org.ietf.jgss,org.bouncycastle.jce.provider;resolution:=optional;version="[1.60,2)"</bundle>

[1] https://github.com/hierynomus/sshj/blob/master/src/main/java/com/hierynomus/sshj/signature/Ed25519PublicKey.java#L37

Thank you! I was considering having to rebuild both libraries to correct the problem. TIL you can wrap the bundle in that manner - excellent.