Recent Changes - Search:

edit SideBar

SSLSockets

Notes about using Vert.x Sockets with SSL. This illustrates the problem, how to tackle it and a solution.

Meta Summary

This nicely illustrates one way to solve problems:

  1. Reproduce the problem
  2. Track down the error message(s)
  3. Search for similar exceptions
  4. Implement a solution

In this case, I had to add better error reporting to accessors because the inner Exception that describes the cause was not being reported.

Problem

Running a model that uses Vert.x and SSL over sockets was failing:

bash-3.2$ $PTII/bin/vergil $PTII/org/terraswarm/accessor/demo/SecureSocket/SecureSocket.xml
$PTII/bin/vergil org/terraswarm/accessor/demo/SecureSocket/SecureSocket.xml
Nov 23, 2015 6:20:56 PM io.vertx.core.net.impl.NetServerImpl
SEVERE: Client from origin /127.0.0.1:63791 failed to connect over ssl
33282 ms. Memory: 381440K Free: 323205K (85%)

In addition, a Ptolemy error window pops up that says: Client: Failed to connect: General SSLEngine Problem

The problems with the above window:

  1. There is no notion of the cause of the error
  2. There is no notion of what code generated the error
  3. The name of the actor that caused the dialog is not shown. It says "Client", which is probably the name, but it is not totally clear to me that it is the name.

A Ptolemy Stack Trace Window with a Go to Actor button would help.

NetServerImpl

On standard out or err, the message

  Nov 23, 2015 6:20:56 PM io.vertx.core.net.impl.NetServerImpl
  SEVERE: Client from origin /127.0.0.1:63791 failed to connect over ssl

Comes from io/vertx/core/net/impl/NetServerImpl.java:

   public void channelActive(ChannelHandlerContext ctx) throws Exception {
      Channel ch = ctx.channel();
      EventLoop worker = ch.eventLoop();

      //Choose a handler                                                                                                                            
      HandlerHolder<NetSocket> handler = handlerManager.chooseHandler(worker);
      if (handler == null) {
        //Ignore                                                                                                                                    
        return;
      }

      if (sslHelper.isSSL()) {
        SslHandler sslHandler = ch.pipeline().get(SslHandler.class);

        io.netty.util.concurrent.Future<Channel> fut = sslHandler.handshakeFuture();
        fut.addListener(future -> {
          if (future.isSuccess()) {
            connected(ch, handler);
          } else {
            log.error("Client from origin " + ch.remoteAddress() + " failed to connect over ssl");
          }
        });
      } else {
        connected(ch, handler);
      }
    }

It looks like io.netty.handler.ssl.SslHandler has a role here.

This seems like a bit of a time sink, so let's look at the other error information.

Ptolemy Error Window

One issue here is that the error window (see above) has no stack trace.

A little sleuthing indicates that ptolemy/actor/lib/jjs/JavaScript.java contains an error(String message) method that is invoked by ptolemy/actor/lib/jjs/VertxHelperBase.java

    protected void _error(ScriptObjectMirror emitter, final String message) {
        _issueResponse(new Runnable() {
            @Override
            public void run() {
                try {
                    emitter.callMember("emit", "error", message);
                    // NOTE: The error handler may not stop execution.                                                                              
                } catch (Throwable ex) {
                    // There may be no error event handler registered.                                                                              
                    // Use the actor to report the error.                                                                                          
                    _actor.error(message);
                }
            }
        });
    }

Adding error(String message, Throwable throwable) to JavaScript.java and modifying _error() in VertxHelperBase to call

                    _actor.error(message, ex);

Means that we get an error window with a stack trace:

The stack trace is:

/Users/cxh/ptII/ptolemy/actor/lib/jjs/external/require.js#209:24<eval>:89:6 Error: Uncaught, unspecified "error" event.
        at jdk.nashorn.internal.objects.NativeError.initException(NativeError.java:137)
        at jdk.nashorn.internal.objects.NativeError.<init>(NativeError.java:102)
        at jdk.nashorn.internal.objects.NativeError.<init>(NativeError.java:106)
        at jdk.nashorn.internal.objects.NativeError.<init>(NativeError.java:110)
        at jdk.nashorn.internal.objects.NativeError.constructor(NativeError.java:129)
        at jdk.nashorn.internal.scripts.Script$Recompilation$730$require.L:1$emit(/Users/cxh/ptII/ptolemy/actor/lib/jjs/external/require.js#209:24<eval>:89)
        at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:631)
        at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:228)
        at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:393)
        at jdk.nashorn.api.scripting.ScriptObjectMirror.callMember(ScriptObjectMirror.java:199)
        at ptolemy.actor.lib.jjs.VertxHelperBase$2.run(VertxHelperBase.java:213)
        at ptolemy.actor.lib.jjs.JavaScript.fire(JavaScript.java:847)
        at ptolemy.domains.de.kernel.DEDirector._fire(DEDirector.java:1942)
        at ptolemy.domains.de.kernel.DEDirector.fire(DEDirector.java:500)
        at ptolemy.actor.CompositeActor.fire(CompositeActor.java:454)
        at ptolemy.actor.Manager.iterate(Manager.java:841)
        at ptolemy.actor.Manager.execute(Manager.java:367)
        at ptolemy.actor.Manager.run(Manager.java:1252)
        at ptolemy.actor.Manager$PtolemyRunThread.run(Manager.java:1905)

Vert.x Example Aside

Maybe looking at this the Vert.x example at https://github.com/vert-x/vertx-examples/blob/master/src/raw/java/ssl/SSLClient.java would help:

import org.vertx.java.core.AsyncResult;
import org.vertx.java.core.AsyncResultHandler;
import org.vertx.java.core.Handler;
import org.vertx.java.core.buffer.Buffer;
import org.vertx.java.core.net.NetSocket;
import org.vertx.java.platform.Verticle;

public class SSLClient extends Verticle {

  public void start() {
    vertx.createNetClient().setSSL(true).setTrustAll(true).connect(1234, "localhost", new AsyncResultHandler<NetSocket>() {
      public void handle(AsyncResult<NetSocket> asyncResult) {
        NetSocket socket = asyncResult.result();
        socket.dataHandler(new Handler<Buffer>() {
          public void handle(Buffer buffer) {
            System.out.println("Net client receiving: " + buffer.toString("UTF-8"));
          }
        });
        //Now send some dataHandler
        for (int i = 0; i < 10; i++) {
          String str = "hello" + i + "\n";
          System.out.print("Net client sending: " + str);
          socket.write(new Buffer(str));
        }
      }
    });
  }
}

This calls setTrustAll(true), which is fine for example code, but not very secure.

Error Handling Aside

The VertxHelperBase error handling was updated to properly include the exception that is being thrown and the actor.

PKIX path building failed

With the change to error handling, the new exception is below:

Nov 24, 2015 10:27:03 AM io.vertx.core.net.impl.NetServerImpl
SEVERE: Client from origin /127.0.0.1:58232 failed to connect over ssl
SocketHelper: Failed to connect: General SSLEngine problem
javax.net.ssl.SSLHandshakeException: General SSLEngine problem
        at sun.security.ssl.Handshaker.checkThrown(Handshaker.java:1431)
        at sun.security.ssl.SSLEngineImpl.checkTaskThrown(SSLEngineImpl.java:535)
        at sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:813)
        at sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:781)
        at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624)
        at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1135)
        at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1025)
        at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:965)
        at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:327)
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:230)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:294)
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:846)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)
        at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112)
        at java.lang.Thread.run(Thread.java:745)
Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
        at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1728)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:304)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)
        at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
        at sun.security.ssl.Handshaker$1.run(Handshaker.java:919)
        at sun.security.ssl.Handshaker$1.run(Handshaker.java:916)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.security.ssl.Handshaker$DelegatedTask.run(Handshaker.java:1369)
        at io.netty.handler.ssl.SslHandler.runDelegatedTasks(SslHandler.java:1161)
        at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1064)
        ... 13 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable\
 to find valid certification path to requested target
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387)
        at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
        at sun.security.validator.Validator.validate(Validator.java:260)
        at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
        at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:281)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:136)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1496)
        ... 21 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:146)
        at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:131)
        at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
        ... 27 more

Search for the Error Message

I searched for

  PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

and StackOverflow had a number of suggestions that boiled down to two choices

  1. Ignore or automatically add the certificate
  2. Add the certificate by hand

Add the cert to cacerts

It looks like the thing to do is to add the cert to the cacerts file

Export the cert:

bash-3.2$ keytool -export -rfc -alias selfsigned -keystore keystore.jks > /tmp/selfsigned.cer
Enter keystore password:  


*****************  WARNING WARNING WARNING  *****************
* The integrity of the information stored in your keystore  *
* has NOT been verified!  In order to verify its integrity, *
* you must provide your keystore password.                  *
*****************  WARNING WARNING WARNING  *****************

bash-3.2$ cat /tmp/selfsigned.cer
-----BEGIN CERTIFICATE-----
MIIDhTCCAm2gAwIBAgIEUj4cWTANBgkqhkiG9w0BAQsFADBzMQswCQYDVQQGEwJVUzELMAkGA1UE
CBMCQ0ExETAPBgNVBAcTCEJlcmtlbGV5MRQwEgYDVQQKEwtVQyBCZXJrZWxleTEYMBYGA1UECxMP
UHRvbGVteSBQcm9qZWN0MRQwEgYDVQQDEwtwdG9sZW15Lm9yZzAeFw0xNTExMjQwMTIzMDVaFw0x
NjExMTgwMTIzMDVaMHMxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTERMA8GA1UEBxMIQmVya2Vs
ZXkxFDASBgNVBAoTC1VDIEJlcmtlbGV5MRgwFgYDVQQLEw9QdG9sZW15IFByb2plY3QxFDASBgNV
BAMTC3B0b2xlbXkub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0DzCpuPGhCnJ
wcUxZbvyFCT3c986JNP9sAXeHeFWoZXCNtjCT7N0MLWpStMNU++FbWzANi8iZuUCla4RutGPgHdJ
69+C+hMoC9BqT3y4cynZMHYMCaoMc0kcWXFcxaljQuUUCzO07uuz8spdLCr1T6AqBYUFh/LtkRAi
IQyU+DZlk9x2jDPfHP36JsntHJIn6JoQuRIC9Kdgz/EabLwIDAc5F2twU+MfpMdHw5VS8jc5+c0M
qUpVq1U5h8mSVYEpIx3zcHRYPJpeoSPWg9dtLz9PLxeefU6s3eCRFde+zJMFhONM4uZFKHtc7htl
UwNoVJAeH1yy3YyT/dugqnE/tQIDAQABoyEwHzAdBgNVHQ4EFgQUp3RTBCn5dj01ot3lqEF/rpZ7
zbMwDQYJKoZIhvcNAQELBQADggEBAAkPRTgF8HVuOliU9ixEqy8iDgHb/TQ5fRqhAeFg4Lwla7Lv
uVTbImWjiDWglLNI5qRnC8t4+x18ZSOd1Dgjvk6SvThm1sPFKCPXPyEq/YL5rLhM4QB11gI9a/Xl
MegcG12A8h7aRoX1JiIXCP8IKhAgwz2CaCTF/df3rnbMQ/QXsfBOYjfxx5bWNrhVBD0C7AjRIoGl
VGKomWDMi2j/Mz17INSclqRVVmd+fllw+U2Yh7BrImQ3fo8KJfXx4mdRx30v0CDrr4JOH+wULCFE
7W5OzUZAdh94OVE8MjVIOFCWpWaXMlCSnpG83RGiGTGuITmKvuMTsbYYzBwJvVOBMLA=
-----END CERTIFICATE-----
bash-3.2$

Find the cacerts file. Under Mac OS X, I have JAVA_HOME set so that I can use ant.

bash-3.2$ echo $JAVA_HOME
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home
bash-3.2$ find /Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home -name cacerts
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/security/cacerts
bash-3.2$

As root, update the cacerts file. The default password is changeit:

bash-3.2$ sudo -i
Password:
ealmac23:~ root# keytool -import -alias selfsigned -keystore /Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/security/cacerts -file /tmp/selfsigned.cer
Enter keystore password:  changeit

Owner: CN=ptolemy.org, OU=Ptolemy Project, O=UC Berkeley, L=Berkeley, ST=CA, C=US
Issuer: CN=ptolemy.org, OU=Ptolemy Project, O=UC Berkeley, L=Berkeley, ST=CA, C=US
Serial number: 523e1c59
Valid from: Mon Nov 23 17:23:05 PST 2015 until: Thu Nov 17 17:23:05 PST 2016
Certificate fingerprints:
         MD5:  31:F4:D1:90:EE:A4:C2:98:F7:90:A2:EB:48:97:24:7B
         SHA1: CD:BF:47:05:A6:0A:43:8A:CD:C7:74:59:24:29:4E:F4:17:F9:0C:7C
         SHA256: 72:28:CD:99:A7:57:D3:25:87:32:25:95:35:06:A2:B6:33:14:40:65:8A:60:96:36:39:7B:AA:12:02:67:94:49
         Signature algorithm name: SHA256withRSA
         Version: 3

Extensions:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: A7 74 53 04 29 F9 76 3D   35 A2 DD E5 A8 41 7F AE  .tS.).v=5....A..
0010: 96 7B CD B3                                        ....
]
]

Trust this certificate? [no]:  yes
yes
Certificate was added to keystore
ealmac23:~ root#

Success!

If I run the model, then it works.

Edit - History - Print - Recent Changes - Search
Page last modified on November 24, 2015, at 09:44 pm