Reputation: 556
I am trying to create a signature as shown below, but I am getting this error:
java.lang.NoSuchFieldError: xmss_SHA256ph
I am using bcprov-jdk15on and bcpkix-jdk15on version 1.64 and Java 8. I have tried various signature algorithms, the latest being SHA1WITHRSA. I have also tried SHA256WITHRSA and SHA256withECDSA.
Do you know why I am getting this error? Thanks.
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
ContentSigner sha1Signer = new JcaContentSignerBuilder(getSignatureAlgorithm()).build(key);
gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new
JcaDigestCalculatorProviderBuilder().build()).build(sha1Signer, cert));
gen.addCertificates(new JcaCertStore(chain));
CMSTypedDataInputStream msg = new CMSTypedDataInputStream(content);
CMSSignedData signedData = gen.generate(msg, false);
signatureBytes = signedData.getEncoded();
The stack trace
java.lang.NoSuchFieldError: xmss_SHA256ph
at org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder.<clinit>(Unknown Source) ~[bcpkix-jdk15on-1.64.jar:1.64.00.0]
at org.bouncycastle.operator.jcajce.JcaContentSignerBuilder.<init>(Unknown Source) ~[bcpkix-jdk15on-1.64.jar:1.64.00.0]
at com.trovare.document.pki.Signer.sign(Signer.java:162) ~[classes/:na]
at org.apache.pdfbox.pdfwriter.COSWriter.doWriteSignature(COSWriter.java:744) ~[pdfbox-2.0.19.jar:2.0.19]
at org.apache.pdfbox.pdfwriter.COSWriter.visitFromDocument(COSWriter.java:1150) ~[pdfbox-2.0.19.jar:2.0.19]
at org.apache.pdfbox.cos.COSDocument.accept(COSDocument.java:452) ~[pdfbox-2.0.19.jar:2.0.19]
at org.apache.pdfbox.pdfwriter.COSWriter.write(COSWriter.java:1386) ~[pdfbox-2.0.19.jar:2.0.19]
at org.apache.pdfbox.pdmodel.PDDocument.saveIncremental(PDDocument.java:1392) ~[pdfbox-2.0.19.jar:2.0.19]
at com.trovare.document.pdf.PdfDcoumentSigner.sign(PdfDcoumentSigner.java:167) ~[classes/:na]
at com.trovare.document.DocumentEncryptorApplication.run(DocumentEncryptorApplication.java:62) [classes/:na]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:784) [spring-boot-2.2.5.RELEASE.jar:2.2.5.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:768) [spring-boot-2.2.5.RELEASE.jar:2.2.5.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:322) [spring-boot-2.2.5.RELEASE.jar:2.2.5.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) [spring-boot-2.2.5.RELEASE.jar:2.2.5.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) [spring-boot-2.2.5.RELEASE.jar:2.2.5.RELEASE]
at com.trovare.document.DocumentEncryptorApplication.main(DocumentEncryptorApplication.java:48) [classes/:na]
I created a new key store and key for each algorithm I tested, using the java keytool. Like this, for example:
keytool -genkey -alias docsigner -keyalg RSA -keysize 2048 -sigalg SHA256withRSA -validity 3650 -keystore keystore.jks
Upvotes: 5
Views: 7571
Reputation: 4225
The underlying reason for errors like this is having more than one instance of Bouncy Castle (BC) implementation in your runtime path. This can manifest in other ways, but this (NoSuchFieldError
in JcaContentSignerBuilder
initialization) is common, as the latter initializes a bunch of fields referencing algorithm identifiers by accessing corresponding fields. If the BC component that carries the identifiers is older, this particular error will show up (BC authors regularly add new algorithms support). It's also one of the easiest to point to version incompatibility, by the way, others can be a lot more subtle.
Now, with practically any other dependency, such is not easy to achieve when using proper build tools (i.e., Maven or Gradle), BC is quite prone to that by means of:
Project, or one of its dependency declares dependency on one or few (but not all) components of BC version A, and another dependency or dependencies declare a dependency on other/all components of BC of version B. This is what happened with OP in this case. The result is a mixture of Bouncy Castle components with different versions, and are going to be incompatible in some way. The solution to this case is to explicitly list version of all known BC components that are used (note that you may not even have direct dependencies on BC, and still need to do that).
BC has different flavors of their libraries, at least those of jdk15on
, jdk18on
and jdk15to18
. Multiple flavors should not be used together, intermixed, and/or be of different versions. However, because the flavors come with different artifact IDs, simply listing all versions/components you want to use is not enough (Your build system does not consider jdk15on
and jdk18on
to be "the same thing" and eligible for collapsing into one). If your code declares a need for BC's jdk15on
version A, but a dependency of your code needs jdk18on
, whether the same or a different version, your build system will use both. To solve this, you'd have to go through all of your direct dependencies, and instruct your build system to not pull the BC dependencies explicitly. As long as the flavor of BC is suitable for the version of the JDK you use at runtime - things should work out.
So, anytime you see weird exceptions involving BC code, especially when used from well-established libraries, the first to do is to get a full dependency tree of your entire project, and ensure that everywhere in the tree you have:
And then keep modifying your build system files until that's achieved.
Upvotes: 0
Reputation: 792
I encountered this but wasn't satisfied by the existing answers which said "just use an old version"!
In my case, I had been managing the following dependencies:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.68</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.68</version>
</dependency>
After a bit of code inspection and looking at the dependency hierarchy, I saw another bouncycastle dependency was being pulled in that was out of sync, namely:
[INFO] +- org.springframework.security.extensions:spring-security-saml2-core:jar:1.0.10.RELEASE:compile
[INFO] | +- com.narupley:not-going-to-be-commons-ssl:jar:0.3.20:compile
[INFO] | | +- org.bouncycastle:bcprov-ext-jdk15on:jar:1.60:compile
Managing the additional dependency to be consistent with the other bouncycastle ones resolved this for me, i.e. I added the following block to dependencyManagement in my POM:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-ext-jdk15on</artifactId>
<version>1.68</version>
</dependency>
Upvotes: 7
Reputation: 556
So, for anyone else who has this issue, mine was fixed by change the version of bouncycastle to 1.60.
I should point out that I tried versions: 1.63, 1.62 and 1.61 and none of the worked. This is what my pom looks like now (or parts of it anyway)
<properties>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<bouncycastle.version>1.60</bouncycastle.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
...
<dependencies>
Upvotes: 3