bouncycastle + JBoss AS7: JCE cannot authenticate

2019-01-13 16:12发布

问题:

I use BouncyCastle for encryption in my application. When I run it standalone, everything works fine. However, if I put it in the webapp and deploy on JBoss server, I get a following error:

javax.servlet.ServletException: error constructing MAC: java.security.NoSuchProviderException: JCE cannot authenticate the provider BC
(...)
root cause
java.lang.Exception: error constructing MAC: java.security.NoSuchProviderException: JCE cannot authenticate the provider BC
(...)
root cause
java.io.IOException: error constructing MAC: java.security.NoSuchProviderException: JCE cannot authenticate the provider BC
    org.bouncycastle.jce.provider.JDKPKCS12KeyStore.engineLoad(Unknown Source)
    java.security.KeyStore.load(Unknown Source)

Here is a part of the code that causes this error:

    if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null)
    {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    }

    // Read the Private Key
    KeyStore ks = KeyStore.getInstance("PKCS12", BouncyCastleProvider.PROVIDER_NAME);
    ks.load(new FileInputStream(certificatePath), privateKeyPassword.toCharArray());

And maven dependency:

<dependency>
    <groupId>bouncycastle</groupId>
    <artifactId>bcmail-jdk16</artifactId>
    <version>140</version>
</dependency>

Do you know how could I deploy it?

回答1:

Do not deploy the bouncy-castle jar as a part of your your webapp (WEB-INF/lib). You need this file in compiliation time of course, but on JBOSS it should be here:

$JBOSS_HOME/server/default/lib/

instead of

yourapp/WEB-INF/lib


回答2:

For JBoss AS7 bouncy castle needs to be deployed as a server module. This replaces the server/default/lib mechanism of earlier versions (as mentioned in Gergely Bacso's answer).

JBoss AS7 uses jdk1.6+. When using JBoss AS7 with jdk1.6 we need to make sure we are using bcprov-jdk16.

Create a Jboss module (a folder $JBOSS_HOME/modules/org/bouncycastle/main). Put the bouncy castle jars that you want to be globally available in it, along with a module.xml file that looks like this:

<module xmlns="urn:jboss:module:1.1" name="org.bouncycastle">
    <resources>
        <resource-root path="bcprov-jdk16-1.46.jar"/>
    </resources>
    <dependencies>
        <module name="javax.api" slot="main" export="true"/>
    </dependencies>
</module>

Once you have setup the module you need to make it available to your deployments. There are two ways:

1. Globally via standalone.xml

In $JBOSS_HOME/standalone/configuration/standalone.xml replace

<subsystem xmlns="urn:jboss:domain:ee:1.0"/>

with

<subsystem xmlns="urn:jboss:domain:ee:1.0">
    <global-modules>
        <module name="org.bouncycastle" slot="main"/>
    </global-modules>
</subsystem>

The jar libraries will now be available across all applications (and this will "emulate" adding to the classpath as was possible in jboss 4,5,6 etc)

2. For a specific deployment (preferred)

Add a module dependency entry to the ear's META-INF/jboss-deployment-structure.xml file, under the section, eg:

<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.1">
    <deployment>
        <dependencies>
            <module name="org.bouncycastle" slot="main" export="true" />
        </dependencies>
    </deployment>
</jboss-deployment-structure>


回答3:

But if You change server from JBoss to other (for example Glassfish) You have the same problem.
The better solition for me are changes in jdk.
You shoud add Bouncy Castle to security providers on Your java platform in two steps:
1. Copy BC librarys (currently bcpkix-jdk15on-149.jar, bcprov-jdk15on-149.jar) to directory $JAVA_HOME/jre/lib/ext/
2. Register BC provider: edit file $JAVA_HOME/jre/lib/security/java.security and under line

security.provider.1=sun.security.provider.Sun

add Your BC provider

security.provider.2=org.bouncycastle.jce.provider.BouncyCastleProvider

Change numbers of rest providers. The whole block of providers should be similar to:

security.provider.1=sun.security.provider.Sun
security.provider.2=org.bouncycastle.jce.provider.BouncyCastleProvider
security.provider.3=sun.security.rsa.SunRsaSign
security.provider.4=sun.security.ec.SunEC
security.provider.5=com.sun.net.ssl.internal.ssl.Provider
security.provider.6=com.sun.crypto.provider.SunJCE
security.provider.7=sun.security.jgss.SunProvider
security.provider.8=com.sun.security.sasl.Provider
security.provider.9=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.10=sun.security.smartcardio.SunPCSC

And now You must just restart the java server.



回答4:

As I put in some other thread it can be also added programmatically by putting the line:

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

Source: jce cannot authenticate the provider bc



回答5:

For those who don't want to change server level config,

<jboss-deployment-structure>  
   <deployment>  
      <resources>  
         <resource-root path="WEB-INF/lib/bcprov-jdk16-1.46.jar" use-physical-code-source="true"/>  
      </resources>  
   </deployment>  
</jboss-deployment-structure>  

adding the bouncy castle jars with use-physical-code-source worked for me