In a XPages application I want to make use of the Dropbox Java SDK (2.1.2) for API v2 to get information about my Dropbox account. The following code is used to retrieve the corresponding account object:
String atoken = "****"; DbxRequestConfig rc = new DbxRequestConfig("****"); DbxClientV2 client = new DbxClientV2(rc,atoken); DbxUserUsersRequests users = client.users(); FullAccount acc = users.getCurrentAccount(); // Exception raised here
The last line raises the following exception:
com.dropbox.core.NetworkIOException: No appropriate protocol at com.dropbox.core.DbxRequestUtil.startPostRaw(DbxRequestUtil.java:240) ... Caused by: javax.net.ssl.SSLHandshakeException: No appropriate protocol at com.ibm.jsse2.kb.c(kb.java:347) ...
From the stacktrace I concluded that IBMJSSE2 is the security provider used to handle the SSL handshake. So I ran the code from above in a non-Domino JVM (JRE7) which uses the SunJSSE security provider and it worked without any problems. Hence the problem must be related to IBM's Domino JVM but I can't figure out how to fix it.
Can anybody help me with this or provide a hint to a solution?
Additional information:
Version of Domino server: 9.0.1 FP4 HF70
Java runtime version: pwa6460sr16fp4-20150414_01 (SR16 FP4) [22B8:0002-1E88]
JVM version: JRE 1.6.0 IBM J9 2.4 Windows 7 amd64-64 jvmwa6460sr16fp4-20150406_242976 (JIT enabled, AOT enabled) J9VM - 20150406_242976 JIT - r9_20150402_88984 GC - GA24_Java6_SR16_20150406_1410_B242976
Unrestricted JCE policy files have been installed in the Domino JVM.
Properties of the IBMJSSE2 security provider:
Alg.Alias.TrustManagerFactory.IbmPKIX = PKIX Alg.Alias.TrustManagerFactory.X.509 = PKIX Alg.Alias.TrustManagerFactory.X509 = PKIX KeyManagerFactory.IbmX509 = com.ibm.jsse2.rc$a_ KeyManagerFactory.NewIbmX509 = com.ibm.jsse2.rc$b_ Provider.id className = com.ibm.jsse2.IBMJSSEProvider2 Provider.id info = IBM JSSE provider2 (implements IbmX509 key/trust factories, SSLv3, TLSv1) Provider.id name = IBMJSSE2 Provider.id version = 1.6 SSLContext.Default = com.ibm.jsse2.tc SSLContext.SSL = com.ibm.jsse2.uc SSLContext.SSL_TLS = com.ibm.jsse2.vc SSLContext.SSL_TLSv2 = com.ibm.jsse2.wc SSLContext.TLS = com.ibm.jsse2.yc SSLContext.TLSv1 = com.ibm.jsse2.zc SSLContext.TLSv1.1 = com.ibm.jsse2.ad SSLContext.TLSv1.2 = com.ibm.jsse2.bd TrustManagerFactory.IbmX509 = com.ibm.jsse2.ed$b_ TrustManagerFactory.PKIX = com.ibm.jsse2.ed$a_
Full stacktrace of exception:
com.dropbox.core.NetworkIOException: No appropriate protocol at com.dropbox.core.DbxRequestUtil.startPostRaw(DbxRequestUtil.java:240) at com.dropbox.core.v2.DbxRawClientV2$1.execute(DbxRawClientV2.java:100) at com.dropbox.core.v2.DbxRawClientV2.executeRetriable(DbxRawClientV2.java:256) at com.dropbox.core.v2.DbxRawClientV2.rpcStyle(DbxRawClientV2.java:97) at com.dropbox.core.v2.users.DbxUserUsersRequests.getCurrentAccount(DbxUserUsersRequests.java:120) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37) at java.lang.reflect.Method.invoke(Method.java:611) at com.ibm.jscript.types.JavaAccessObject.call(JavaAccessObject.java:321) at com.ibm.jscript.types.FBSObject.call(FBSObject.java:161) at com.ibm.jscript.ASTTree.ASTCall.interpret(ASTCall.java:197) at com.ibm.jscript.ASTTree.ASTAssign.interpret(ASTAssign.java:91) at com.ibm.jscript.ASTTree.ASTBlock.interpret(ASTBlock.java:100) at com.ibm.jscript.ASTTree.ASTTry.interpret(ASTTry.java:109) at com.ibm.jscript.ASTTree.ASTBlock.interpret(ASTBlock.java:100) at com.ibm.jscript.ASTTree.ASTTry.interpret(ASTTry.java:109) at com.ibm.jscript.std.FunctionObject._executeFunction(FunctionObject.java:261) at com.ibm.jscript.std.FunctionObject.executeFunction(FunctionObject.java:185) at com.ibm.jscript.std.FunctionObject.call(FunctionObject.java:171) at com.ibm.jscript.types.FBSObject.call(FBSObject.java:161) at com.ibm.jscript.ASTTree.ASTCall.interpret(ASTCall.java:197) at com.ibm.jscript.ASTTree.ASTAssign.interpret(ASTAssign.java:91) at com.ibm.jscript.ASTTree.ASTBlock.interpret(ASTBlock.java:100) at com.ibm.jscript.ASTTree.ASTIf.interpret(ASTIf.java:85) at com.ibm.jscript.ASTTree.ASTProgram.interpret(ASTProgram.java:119) at com.ibm.jscript.types.FBSGlobalObject$GlobalMethod.call(FBSGlobalObject.java:280) at com.ibm.jscript.types.FBSObject.call(FBSObject.java:161) at com.ibm.jscript.types.FBSGlobalObject$GlobalMethod.call(FBSGlobalObject.java:219) at com.ibm.jscript.ASTTree.ASTCall.interpret(ASTCall.java:197) at com.ibm.jscript.ASTTree.ASTBlock.interpret(ASTBlock.java:100) at com.ibm.jscript.ASTTree.ASTIf.interpret(ASTIf.java:85) at com.ibm.jscript.ASTTree.ASTBlock.interpret(ASTBlock.java:100) at com.ibm.jscript.ASTTree.ASTTry.interpret(ASTTry.java:109) at com.ibm.jscript.std.FunctionObject._executeFunction(FunctionObject.java:261) at com.ibm.jscript.std.FunctionObject.executeFunction(FunctionObject.java:185) at com.ibm.jscript.std.FunctionObject.call(FunctionObject.java:171) at com.ibm.jscript.std.FunctionPrototype$FunctionMethod.call(FunctionPrototype.java:169) at com.ibm.jscript.types.FBSObject.call(FBSObject.java:161) at com.ibm.jscript.ASTTree.ASTCall.interpret(ASTCall.java:197) at com.ibm.jscript.ASTTree.ASTAssign.interpret(ASTAssign.java:91) at com.ibm.jscript.ASTTree.ASTBlock.interpret(ASTBlock.java:100) at com.ibm.jscript.ASTTree.ASTIf.interpret(ASTIf.java:85) at com.ibm.jscript.ASTTree.ASTBlock.interpret(ASTBlock.java:100) at com.ibm.jscript.ASTTree.ASTTry.interpret(ASTTry.java:109) at com.ibm.jscript.ASTTree.ASTProgram.interpret(ASTProgram.java:119) at com.ibm.jscript.ASTTree.ASTProgram.interpretEx(ASTProgram.java:139) at com.ibm.jscript.JSExpression._interpretExpression(JSExpression.java:435) at com.ibm.jscript.JSExpression.access$1(JSExpression.java:424) at com.ibm.jscript.JSExpression$2.run(JSExpression.java:414) at java.security.AccessController.doPrivileged(AccessController.java:448) at com.ibm.jscript.JSExpression.interpretExpression(JSExpression.java:410) at com.ibm.jscript.JSExpression.evaluateValue(JSExpression.java:251) at com.ibm.jscript.JSExpression.evaluateValue(JSExpression.java:234) at com.ibm.xsp.javascript.JavaScriptInterpreter.interpret(JavaScriptInterpreter.java:222) at com.ibm.xsp.binding.javascript.JavaScriptMethodBinding.invoke(JavaScriptMethodBinding.java:111) at com.ibm.xsp.component.UIViewRootEx.invokePhaseMethodBinding(UIViewRootEx.java:1735) at com.ibm.xsp.controller.FacesControllerImpl.invokePhaseMethodBinding(FacesControllerImpl.java:450) at com.ibm.xsp.controller.FacesControllerImpl.access$0(FacesControllerImpl.java:444) at com.ibm.xsp.controller.FacesControllerImpl$ViewPhaseListener.afterPhase(FacesControllerImpl.java:512) at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:218) at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:120) at com.ibm.xsp.controller.FacesControllerImpl.render(FacesControllerImpl.java:270) at com.ibm.xsp.webapp.FacesServlet.serviceView(FacesServlet.java:261) at com.ibm.xsp.webapp.FacesServletEx.serviceView(FacesServletEx.java:157) at com.ibm.xsp.webapp.FacesServlet.service(FacesServlet.java:160) at com.ibm.xsp.webapp.FacesServletEx.service(FacesServletEx.java:138) at com.ibm.xsp.webapp.DesignerFacesServlet.service(DesignerFacesServlet.java:103) at com.ibm.designer.runtime.domino.adapter.ComponentModule.invokeServlet(ComponentModule.java:576) at com.ibm.domino.xsp.module.nsf.NSFComponentModule.invokeServlet(NSFComponentModule.java:1335) at com.ibm.designer.runtime.domino.adapter.ComponentModule$AdapterInvoker.invokeServlet(ComponentModule.java:853) at com.ibm.designer.runtime.domino.adapter.ComponentModule$ServletInvoker.doService(ComponentModule.java:796) at com.ibm.designer.runtime.domino.adapter.ComponentModule.doService(ComponentModule.java:565) at com.ibm.domino.xsp.module.nsf.NSFComponentModule.doService(NSFComponentModule.java:1319) at com.ibm.domino.xsp.module.nsf.NSFService.doServiceInternal(NSFService.java:662) at com.ibm.domino.xsp.module.nsf.NSFService.doService(NSFService.java:482) at com.ibm.designer.runtime.domino.adapter.LCDEnvironment.doService(LCDEnvironment.java:357) at com.ibm.designer.runtime.domino.adapter.LCDEnvironment.service(LCDEnvironment.java:313) at com.ibm.domino.xsp.bridge.http.engine.XspCmdManager.service(XspCmdManager.java:272) Caused by: javax.net.ssl.SSLHandshakeException: No appropriate protocol at com.ibm.jsse2.kb.c(kb.java:347) at com.ibm.jsse2.SSLSocketImpl.i(SSLSocketImpl.java:363) at com.ibm.jsse2.SSLSocketImpl.h(SSLSocketImpl.java:650) at com.ibm.jsse2.SSLSocketImpl.a(SSLSocketImpl.java:669) at com.ibm.jsse2.SSLSocketImpl.startHandshake(SSLSocketImpl.java:95) at com.ibm.net.ssl.www2.protocol.https.c.afterConnect(c.java:162) at com.ibm.net.ssl.www2.protocol.https.d.connect(d.java:36) at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1044) at com.ibm.net.ssl.www2.protocol.https.b.getOutputStream(b.java:53) at com.dropbox.core.http.StandardHttpRequestor.getOutputStream(StandardHttpRequestor.java:123) at com.dropbox.core.http.StandardHttpRequestor.access$000(StandardHttpRequestor.java:28) at com.dropbox.core.http.StandardHttpRequestor$Uploader.(StandardHttpRequestor.java:133) at com.dropbox.core.http.StandardHttpRequestor.startPost(StandardHttpRequestor.java:72) at com.dropbox.core.http.StandardHttpRequestor.startPost(StandardHttpRequestor.java:28) at com.dropbox.core.DbxRequestUtil.startPostRaw(DbxRequestUtil.java:232) ...
Update: After setting javax.net.debug=ssl:handshake:data
(as suggested by Jigar Joshi) the error log and trace log provide the following additional information:
Certificate with subject EMAILADDRESS=****, CN=****, O=****, L=****, ST=****, C=****, issued by CN=****, OU=****, O=****, C=****, is not trusted. Validation failed with error 3659.
CommonBaseEventLogRecord:sourceClassName = com.ibm.domino.napi.ssl.DominoX509TrustManager CommonBaseEventLogRecord:sourceMethodName = checkServerTrusted <sourcecomponentid component="Expeditor 6.2" componentidtype="ProductName" instanceid="" location="****" locationtype="Hostname" subcomponent="com.ibm.domino.napi.ssl" threadid="5" componenttype="http://www.w3.org/2001/XMLSchema-instance">
The certificate that is not trusted is my own, even though all certificates and the private key were imported into my keystore. The fact that the keystore works in the non-Domino JVM allows me to conclude that the keystore file should be valid. Yet, the certificate is still not trusted when running the code in the Domino JVM.
Update: The core part of the debug output (javax.net.debug=ssl:handshake
) is
SSLContextImpl: Using X509ExtendedKeyManager com.ibm.jsse2.hd SSLContextImpl: Using X509TrustManager com.ibm.jsse2.pc IBMJSSE2 will ignore com.ibm.jsse2.overrideDefaultProtocol since was set to a non recognized value TLSv1 Installed Providers = IBMJSSE2, IBMJCE, IBMJGSSProvider, IBMCertPath, IBMSASL, IBMXMLCRYPTO, IBMXMLEnc, Policy, IBMSPNEGO JsseJCE: Using SecureRandom IBMSecureRandom from provider IBMJCE version 1.2 trigger seeding of SecureRandom done seeding SecureRandom IBMJSSE2 will enable CBC protection IBMJSSE2 to send SCSV Cipher Suite on initial ClientHello JsseJCE: Using SecureRandom IBMSecureRandom from provider IBMJCE version 1.2 IBMJSSE2 will allow RFC 5746 renegotiation per com.ibm.jsse2.renegotiate set to none or default IBMJSSE2 will not require renegotiation indicator during initial handshake per com.ibm.jsse2.renegotiation.indicator set to OPTIONAL or default taken IBMJSSE2 will not perform identity checking against the peer cert check during renegotiation per com.ibm.jsse2.renegotiation.peer.cert.check set to OFF or default IBMJSSE2 will not allow unsafe server certificate change during renegotiation per jdk.tls.allowUnsafeServerCertChange set to FALSE or default Is initial handshake: true JsseJCE: Using KeyAgreement ECDH from provider IBMJCE version 1.2 JsseJCE: Using signature SHA1withECDSA from provider TBD via init JsseJCE: Using signature NONEwithECDSA from provider TBD via init JsseJCE: Using KeyFactory EC from provider IBMJCE version 1.2 JsseJCE: Using KeyPairGenerator EC from provider TBD via init JsseJce: EC is available Ignoring disabled cipher suite: SSL_RENEGO_PROTECTION_REQUEST for TLSv1 No available cipher suite for TLSv1 Thread-8, handling exception: javax.net.ssl.SSLHandshakeException: No appropriate protocol Thread-8, SEND TLSv1 ALERT: fatal, description = handshake_failure
"No available cipher suite for TLSv1" seems to be the root of my problem.
Update: Getting the default SSL server socket factory (SSLServerSocketFactory.getDefault()
) and the corresponding default and supported cipher suites (getDefaultCipherSuites()
/ getSupportedCipherSuites()
) revealed that only SSL cipher suites are available:
SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA [supported] SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA [default] SSL_DHE_DSS_WITH_AES_128_CBC_SHA [default] SSL_DHE_DSS_WITH_AES_128_CBC_SHA256 [supported] SSL_DHE_DSS_WITH_AES_128_GCM_SHA256 [supported] SSL_DHE_DSS_WITH_AES_256_CBC_SHA [default] SSL_DHE_DSS_WITH_AES_256_CBC_SHA256 [supported] SSL_DHE_DSS_WITH_AES_256_GCM_SHA384 [supported] SSL_DHE_DSS_WITH_DES_CBC_SHA [default] SSL_DHE_DSS_WITH_RC4_128_SHA [supported] SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA [supported] SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA [default] SSL_DHE_RSA_WITH_AES_128_CBC_SHA [default] SSL_DHE_RSA_WITH_AES_128_CBC_SHA256 [supported] SSL_DHE_RSA_WITH_AES_128_GCM_SHA256 [supported] SSL_DHE_RSA_WITH_AES_256_CBC_SHA [default] SSL_DHE_RSA_WITH_AES_256_CBC_SHA256 [supported] SSL_DHE_RSA_WITH_AES_256_GCM_SHA384 [supported] SSL_DHE_RSA_WITH_DES_CBC_SHA [default] SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA [supported] SSL_DH_anon_EXPORT_WITH_RC4_40_MD5 [supported] SSL_DH_anon_WITH_3DES_EDE_CBC_SHA [supported] SSL_DH_anon_WITH_AES_128_CBC_SHA [supported] SSL_DH_anon_WITH_AES_128_CBC_SHA256 [supported] SSL_DH_anon_WITH_AES_128_GCM_SHA256 [supported] SSL_DH_anon_WITH_AES_256_CBC_SHA [supported] SSL_DH_anon_WITH_AES_256_CBC_SHA256 [supported] SSL_DH_anon_WITH_AES_256_GCM_SHA384 [supported] SSL_DH_anon_WITH_DES_CBC_SHA [supported] SSL_DH_anon_WITH_RC4_128_MD5 [supported] SSL_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA [supported] SSL_ECDHE_ECDSA_WITH_AES_128_CBC_SHA [supported] SSL_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 [supported] SSL_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 [supported] SSL_ECDHE_ECDSA_WITH_AES_256_CBC_SHA [supported] SSL_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 [supported] SSL_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 [supported] SSL_ECDHE_ECDSA_WITH_NULL_SHA [supported