Closed iyashsoni closed 5 years ago
Thanks for the bug report! It looks like you're doing everything right. How did you generate the VAPID keys?
@MartijnDwars I’m using the npm module web push to generate keys. The weird part is, the same piece of code runs perfectly fine when run from a plain java program - a separate java project with only one file.
I’ve debugged my main java project and the final exception is thrown from the key agreement class.
Any help? Thanks.
@MartijnDwars Update: When I debugged through the code - I see method checkKey of sun.security.ec.ECKeyFactory class gets invoked. This is the origin of the error.
I have stepped through the code in both - my Push Server and a plain Push Java sample side by side. Everything is same, until the following function is triggered: It is in javax.crypto.KeyAgreement Class:
private void chooseProvider(int var1, Key var2, AlgorithmParameterSpec var3, SecureRandom var4) throws InvalidKeyException, InvalidAlgorithmParameterException {
synchronized(this.lock) {
if (this.spi != null) {
this.implInit(this.spi, var1, var2, var3, var4);
} else {
Exception var6 = null;
while(true) {
Service var7;
do {
do {
if (this.firstService == null && !this.serviceIterator.hasNext()) {
if (var6 instanceof InvalidKeyException) {
throw (InvalidKeyException)var6;
}
if (var6 instanceof InvalidAlgorithmParameterException) {
throw (InvalidAlgorithmParameterException)var6;
}
if (var6 instanceof RuntimeException) {
throw (RuntimeException)var6;
}
String var12 = var2 != null ? var2.getClass().getName() : "(null)";
throw new InvalidKeyException("No installed provider supports this key: " + var12, var6);
}
if (this.firstService != null) {
var7 = this.firstService;
this.firstService = null;
} else {
var7 = (Service)this.serviceIterator.next();
}
} while(!var7.supportsParameter(var2));
} while(!JceSecurity.canUseProvider(var7.getProvider()));
try {
KeyAgreementSpi var8 = (KeyAgreementSpi)var7.newInstance((Object)null);
this.implInit(var8, var1, var2, var3, var4);
this.provider = var7.getProvider();
this.spi = var8;
this.firstService = null;
this.serviceIterator = null;
return;
} catch (Exception var10) {
if (var6 == null) {
var6 = var10;
}
}
}
}
}
}
Here this.serviceIterator contains two elements in both the programs - these are: BC: KeyAgreement.ECDH -> org.bouncycastle.jcajce.provider.asymmetric.ec.KeyAgreementSpi$DH SunEC: KeyAgreement.ECDH -> sun.security.ec.ECDHKeyAgreement
The only difference is: In my Push Server, JceSecurity.canUseProvider(var7.getProvider()) gives false for Bouncy Castle while it gives true in the case of Plain Java Push Sample.
Hence when var7.getProvider() is called in the final try block, we get BouncyCastle Prov correctly in Java Sample and we get SunEC Prov in my Push Server.
As a result, in implInit method of KeyAgreement class:
private void implInit(KeyAgreementSpi var1, int var2, Key var3, AlgorithmParameterSpec var4, SecureRandom var5) throws InvalidKeyException, InvalidAlgorithmParameterException {
if (var2 == 1) {
var1.engineInit(var3, var5);
} else {
var1.engineInit(var3, var4, var5);
}
}
In Push Sample, var1 is instance of class org.bouncycastle.jcajce.provider.asymmetric.ec.KeyAgreementSpi$DH with following values:
In my Push Server, var1 is instance of class sun.security.ec.ECDHKeyAgreement with privateKey, publicKey = null and secretLen = 0
As a final result, in my Push Server, I get: Not an EC key: ECDH Error from checkKey method in sun.security.ec.ECKeyFactory:
I am completely unaware of what can be the reason for this. I thought this info might be helpful to you.
Thanks.
Thanks for the detailed analysis! The problem seems to be that JceSecurity.canUseProvider
returns false for the BouncyCastle provider. This method from the standard library verifies if the JAR is a signed provider JAR file. The BouncyCastle JARs are signed, but it's possible that your deployment unpacks/repacks the JAR and thereby removes the signature. Can you check if the original BouncyCastle JAR is on your classpath?
Hey @MartijnDwars, I got past this error with Reflection and dynamic class loading. Now I've hit across this SSL handshake error:
A signer with SubjectDN C=US,ST=California,L=Mountain View,O=Google
LLC,CN=edgecert.googleapis.com was sent from the target host. The signer might need to be added to
local trust store /Users/yashsoni/MobileFirst-8.0.0.0/mfp-
server/usr/servers/mfp/resources/security/svkpush-PKCS-12.p12, located in SSL configuration alias
defaultSSLConfig. The extended error message from the SSL handshake exception is: PKIX path building
failed: java.security.cert.CertPathBuilderException: No issuer certificate for certificate in certification path
found.
Any idea?
The signer might need to be added to local trust store /Users/yashsoni/MobileFirst-8.0.0.0/mfp-server/usr/servers/mfp/resources/security/svkpush-PKCS-12.p12
It looks like you're running your JVM with a custom trust store that does not contain Google's root certificate. The error hints at a solution: add the signer to the local trust store. You'll have to Google on how to do this exactly, but maybe you can start at the following references:
Thanks, @MartijnDwars for the help. I'm closing this issue as it is solved.
Constantly getting Exception in thread "main" java.security.InvalidKeyException: Not an EC key: ECDH
Environment Info: MacOS, Java 1.8
I've tried the solution mentioned in this issue but still no luck.
I have done the following:
/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext/
This is the stack trace:
This is the Subscription Class:
The sendNotification Method:
P.S.: Don't know if it helps but I am building a final war file of the PushService and deploying in my local environment.
Let me know if more information is required. Thanks, Yash Soni