安卓SSLEngine示例

6
我需要在我正在开发的应用程序中使用TCP套接字上的TLS。我已经浏览了数十个示例,虽然我没有问题通过握手,但我似乎无法通过任何方式读取输入流(尝试了很多,包括readline()、读取到字符数组等)。每次我尝试时,应用程序都会在那个位置冻结。如果我调试,它永远不会进入下一行代码。
在尝试解决问题时,我决定转向使用SSLEngine,因为这是Java 1.5对于SSL的java.nio的答案。然而,我只找到了一个示例(在这里:http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/samples/sslengine/SSLEngineSimpleDemo.java),对我来说有点混乱,我没有成功实现它。当我尝试时,unwrap()调用产生了一个空缓冲区,而我知道(从在命令行上使用OpenSSL)所涉及的服务将数据推回管道。
欢迎提出建议,我已经花费了太多时间在这上面了。以下是相关代码:

SSLEngine engine = sslContext.createSSLEngine(uri.getHost(), uri.getPort());
            engine.setUseClientMode(true);
            engine.beginHandshake();
            SSLSession session = engine.getSession();
            int bufferMax = session.getPacketBufferSize();
            int appBufferMax = session.getApplicationBufferSize() + 50;
            ByteBuffer cTo = ByteBuffer.allocateDirect(bufferMax);
            ByteBuffer sTo = ByteBuffer.allocateDirect(bufferMax);

            ByteBuffer out = ByteBuffer.wrap(sessionId.getBytes());
            ByteBuffer in = ByteBuffer.allocate(appBufferMax);


            debug("sending secret");
            SSLEngineResult rslt = engine.wrap(out, cTo);
            debug("first result: " + rslt.toString());
            sTo.flip();
            rslt = engine.unwrap(sTo, in);
            debug("next result" + rslt.toString());

作为更新,我还尝试在unwrap调用上循环,直到(rslt.getStatus() != SSLEngineResult.Status.OK),但它从未填充,状态也从未变为OK。 - Paul
你尝试在普通的Java应用程序中运行这段代码了吗?这至少可以帮助确定它是否是特定于Android的问题。 - Eric Levine
是的,我不认为这是特定于安卓的,我只是碰巧在安卓项目中进行。 - Paul
4个回答

1

这个实现缺少一些关键部分。即握手可以在几个状态之间反弹,包括NEED_WRAP、NEED_UNWRAP、NEED_TASK来协商连接。这意味着你不能只调用一个然后调用另一个。你需要循环遍历这些状态,直到握手完成。

   while (handshaking) {
      switch (state) {
          case NEED_WRAP:
              doWrap();
              break;
          case NEED_UNWRAP:
              doUnwrap();
              break;
          case NEED_TASK:
              doTask();
              break;
        }
    }

Java SSL和NIO的完整工作示例

话虽如此,您应该知道{{link2:Android上的SSLEngine存在问题}}。根据该线程,Google建议使用线程和阻塞套接字。


Android上的SSLEngine也以不同的方式出现了故障。请参见https://issuetracker.google.com/issues/37044892。 - Stephen M -on strike-

1
我写了一些东西,使得使用SSLEngine更容易。它可以与NIO一起使用或用于其他用例。可在此处获取SSLFacade

0

unwrap() 如果解封的是 SSL 握手消息或警报,而不是应用程序数据,则可能产生空缓冲区。这里没有足够的信息来进一步说明。引擎状态以后如何?


0

beginHandshake 不会执行握手,它只是用来通知 SSLEngine 你想要在下一次 wrap/unwrap 调用中执行握手。当你想要进行另一个握手时,这非常有用。对于初始握手,不需要使用它,因为第一次调用 wrap 将启动握手。

此外,你必须检查 wrap 和 unwrap 方法的结果,以确定所有数据是否已正确编码。可能需要多次调用这些方法才能处理所有数据。

以下链接可能会有所帮助: http://onjava.com/onjava/2004/11/03/ssl-nio.html

或者这个问题: SSL Handshaking Using Self-Signed Certs and SSLEngine (JSSE)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接