I am adding support for FIDO U2F to my J2EE application (which is basicaly securing login with hardware token). I am using library from yubico, u2flib-server-core, which handles cryptographic operations in protocol using BouncyCastleCrypto. Hovewer, while decoding public key from persistent storage I keep getting exception with message
"key spec not recognized"
I have narrowed problem down to this function from library
public PublicKey decodePublicKey(byte[] encodedPublicKey) throws U2fBadInputException {
try {
X9ECParameters curve = SECNamedCurves.getByName("secp256r1");
ECPoint point;
try {
point = curve.getCurve().decodePoint(encodedPublicKey);
} catch (RuntimeException e) {
throw new U2fBadInputException("Could not parse user public key", e);
}
return KeyFactory.getInstance("ECDSA").generatePublic(
new ECPublicKeySpec(point,
new ECParameterSpec(
curve.getCurve(),
curve.getG(),
curve.getN(),
curve.getH()
)
)
);
} catch (GeneralSecurityException e) { //This should not happen
throw new RuntimeException(e);
}
}
Method generatePublic throws exception which is caught and rethrown as RuntimeException.
I have verified that KeyFactory.getInstance returns KeyFactory, from BC provider. Running this code outside Wildfly works perfectly. (I had to put bcprov-ext-jdk15on-154.jar into /lib/ext of java).
I have already tried updating wildfly's module for bouncycastle, currently I have added all 6 jars published on http://www.bouncycastle.org/latest_releases.html
Interesting part from stack trace is
java.security.spec.InvalidKeySpecException: key spec not recognised
at org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi.engineGeneratePublic(Unknown Source)
at org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi.engineGeneratePublic(Unknown Source)
at java.security.KeyFactory.generatePublic(KeyFactory.java:334)
at com.yubico.u2f.crypto.BouncyCastleCrypto.decodePublicKey(BouncyCastleCrypto.java:60)
at com.yubico.u2f.data.messages.key.RawAuthenticateResponse.checkSignature(RawAuthenticateResponse.java:64)
at com.yubico.u2f.U2fPrimitives.finishAuthentication(U2fPrimitives.java:153)
at com.yubico.u2f.U2F.finishAuthentication(U2F.java:116)
at com.yubico.u2f.U2F.finishAuthentication(U2F.java:90)
Hope someone can help me :-) Thanks in advance
EDIT: I have tried that code with other modes and look like not event single one gets recognized. Using EC The excpetion is different because it uses other provider, however configuring providers list that BC is on the top yelds still same exception as I mentioned.
EDIT I think it might be a some sort of classloading issue so i turned verbose logging on and here is interesting Logs
[Loaded org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi$ECDSA from file:/home/martin/java/jdk1.8.0_45/jre/lib/ext/bcprov-jdk15on-154.jar]
[Loaded org.bouncycastle.jce.spec.ECKeySpec from jar:file:/opt/wildfly-10.0.0.Final/modules/system/layers/base/org/bouncycastle/main/bcprov-jdk15on-1.52.jar!/]
KeyFactorySpi and ECKeySpec are comming from two different jars (classloaders?) hence the instanceof used in KeyFactory fails
Finally found issue :-)
When I turned on verbose logging of classloaders i found that KeySpec is comming from different classloader as KeyFactorySpi which checked instanceof that KeySpec. It's problem that I have caused during solving this issue. As wildfly 10 is shipped with BouncyCastle module, on which RestEasy depends, it gets loaded. Hovever library that I have used also shipped some BouncyCastle classes.
All i had to do was create jboss-deployment-structure.xml with following contents
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.1">
<deployment>
<dependencies>
<module name="org.bouncycastle" />
</dependencies>
</deployment>
</jboss-deployment-structure>
This allowed me to use wildfly's module for BouncyCastle. Hovewer, when I have done this I have already tried to put BouncyCastle in lib/ext/ of JRE that I have used to run server with. This caused exact same error with another cause :-)
So to sum up, when using BouncyCastle with wildfly 10 you have to ensure following:
Hope this helps someone in the future :-)