Java HTTPS服务器代码失败

时间:2015-12-03 19:45:14

标签: java ssl https server

我一直在尝试用Java实现HTTPS / SSL服务器,我尝试过使用许多不同的代码示例,但是在服务器读取请求时,它们似乎都失败了。下面是我一直在使用的一个示例,当我使用Firefox运行时,我收到此错误:

[write] MD5 and SHA1 hashes:  len = 16
0000: 14 00 00 0C 73 A7 11 73   AE 3C 41 C5 91 C7 E9 19  ....s..s.<A.....
Padded plaintext before ENCRYPTION:  len = 16
0000: 14 00 00 0C 73 A7 11 73   AE 3C 41 C5 91 C7 E9 19  ....s..s.<A.....
main, WRITE: TLSv1.2 Handshake, length = 40
main, waiting for close_notify or alert: state 1
main, Exception while waiting for close java.net.SocketException: Software         caused connection abort: recv failed
main, handling exception: java.net.SocketException: Software caused     connection abort: recv failed
%% Invalidated:  [Session-1, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
 Priv exp --- null
 Exception occurred .... java.net.SocketException: Software caused     connection abort: recv failed
java.net.SocketException: Software caused connection abort: recv failed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at sun.security.ssl.InputRecord.readFully(Unknown Source)
at sun.security.ssl.InputRecord.read(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.waitForClose(Unknown Source)
at sun.security.ssl.HandshakeOutStream.flush(Unknown Source)
at sun.security.ssl.Handshaker.sendChangeCipherSpec(Unknown Source)
at sun.security.ssl.ServerHandshaker.sendChangeCipherAndFinish(Unknown Source)
at sun.security.ssl.ServerHandshaker.clientFinished(Unknown Source)
at sun.security.ssl.ServerHandshaker.processMessage(Unknown Source)
at sun.security.ssl.Handshaker.processLoop(Unknown Source)
at sun.security.ssl.Handshaker.process_record(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readDataRecord(Unknown Source)
at sun.security.ssl.AppInputStream.read(Unknown Source)
at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)
at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
at sun.nio.cs.StreamDecoder.read(Unknown Source)
at java.io.InputStreamReader.read(Unknown Source)
at java.io.BufferedReader.fill(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at SSLServer.main(SSLServer.java:65)

,这是代码:

import java.io.*;
import java.security.Security;
import java.security.PrivilegedActionException;

import javax.net.ssl.*;
import com.sun.net.ssl.*;
import com.sun.net.ssl.internal.ssl.Provider;

/**
 * @author Joe Prasanna Kumar
 * This program simulates an SSL Server listening on a specific port for client requests
 * 
 * Algorithm:
 * 1. Regsiter the JSSE provider
 * 2. Set System property for keystore by specifying the keystore which contains the server certificate
 * 3. Set System property for the password of the keystore which contains the server certificate
 * 4. Create an instance of SSLServerSocketFactory
 * 5. Create an instance of SSLServerSocket by specifying the port to which the SSL Server socket needs to bind with
 * 6. Initialize an object of SSLSocket
 * 7. Create InputStream object to read data sent by clients
 * 8. Create an OutputStream object to write data back to clients.
 * 
 */ 


public class SSLServer {

/**
 * @param args
 */

public static void main(String[] args) throws Exception{

    int intSSLport = 4443; // Port where the SSL Server needs to listen for new requests from the client

    {
        // Registering the JSSE provider
        Security.addProvider(new Provider());

        //Specifying the Keystore details
        System.setProperty("javax.net.ssl.keyStore","C:\\Users\\test\\Eclipse-workspaces\\Test\\newkeystore.jks");
        System.setProperty("javax.net.ssl.keyStorePassword","changeit");

        // Enable debugging to view the handshake and communication which happens between the SSLClient and the SSLServer
        System.setProperty("javax.net.debug","all");
    }

    try {
            // Initialize the Server Socket
            SSLServerSocketFactory sslServerSocketfactory = (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
            SSLServerSocket sslServerSocket = (SSLServerSocket)sslServerSocketfactory.createServerSocket(intSSLport);
            SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept();

            // Create Input / Output Streams for communication with the client
            while(true)
            {
            PrintWriter out = new PrintWriter(sslSocket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(
                    new InputStreamReader(
                            sslSocket.getInputStream()));
            String inputLine, outputLine;

            System.out.println("Start reading socket");

            while ((inputLine = in.readLine()) != null) {
                 //out.println(inputLine);
                 System.out.println(inputLine);
            }

            System.out.println("Finished reading socket");

            // Send the response
            // Send the headers
            out.println("HTTP/1.0 200 OK");
            out.println("Content-Type: text/html");
            out.println("Server: Bot");
            // this blank line signals the end of the headers
            out.println("");
            // Send the HTML page
            out.println("<H1>Welcome to the Ultra Mini-WebServer</H2>");
            out.flush();

            // Close the streams and the socket
            out.close();
            in.close();
            sslSocket.close();
            sslServerSocket.close();

            }
        }


    catch(Exception exp)
    {
        PrivilegedActionException priexp = new PrivilegedActionException(exp);
        System.out.println(" Priv exp --- " + priexp.getMessage());

        System.out.println(" Exception occurred .... " +exp);
        exp.printStackTrace();
    }

}

}

正如我所说的那样,我尝试了许多类似的其他示例程序,在读取请求后,它们似乎都在同一区域失败。

请注意,如果我使用openssl s_client并手动输入相同的输入请求,则可以正常工作。

任何人都可以帮我指出可能出错的地方吗?

谢谢, 吉姆

编辑:

我认为我已经取得了一些进展,使用了不同的示例服务器代码,来自这里:

http://www.herongyang.com/JDK/HTTPS-Server-Test-Program-HttpsHello.html

首先,再次,如果我运行此应用程序并从“openssl s_client”点击它,当我手动输入“GET”时它可以正常工作。

但是,如果我尝试使用Firefox,只要我向https://192.168.0.6:8888发送请求(仅供参考,如果我使用与cert匹配的主机名无关紧要),我会弹出一个要求我添加异常,也是,我得到了app / server端:

Server started:
Server socket class: class sun.security.ssl.SSLServerSocketImpl
   Socket address = 0.0.0.0/0.0.0.0
   Socket port = 8888
   Need client authentication = false
   Want client authentication = false
   Use client mode = false
Socket class: class sun.security.ssl.SSLSocketImpl
   Remote address = /192.168.0.5
   Remote port = 58972
   Local socket address = /192.168.0.5:8888
   Local address = /192.168.0.5
   Local port = 8888
   Need client authentication = false
   Cipher suite = SSL_NULL_WITH_NULL_NULL
   Protocol = NONE
Read=[null]
java.net.SocketException: Connection closed by remote host
    at sun.security.ssl.SSLSocketImpl.checkWrite(Unknown Source)
    at sun.security.ssl.AppOutputStream.write(Unknown Source)
    at sun.nio.cs.StreamEncoder.writeBytes(Unknown Source)
    at sun.nio.cs.StreamEncoder.implFlushBuffer(Unknown Source)
    at sun.nio.cs.StreamEncoder.implFlush(Unknown Source)
    at sun.nio.cs.StreamEncoder.flush(Unknown Source)
    at java.io.OutputStreamWriter.flush(Unknown Source)
    at java.io.BufferedWriter.flush(Unknown Source)
    at HttpsHello.main(HttpsHello.java:43)

所以,我做了不同的事情。

我启动了Firefox,然后转到选项 - &gt;高级 - &gt;证书 - &gt;添加例外

对于例外,我将URL用于获取证书https://192.168.0.5:8888

点击“获取证书”后,应用程序就爆炸了:

Server started:
Server socket class: class sun.security.ssl.SSLServerSocketImpl
   Socket address = 0.0.0.0/0.0.0.0
   Socket port = 8888
   Need client authentication = false
   Want client authentication = false
   Use client mode = false
Socket class: class sun.security.ssl.SSLSocketImpl
   Remote address = /192.168.0.5
   Remote port = 59018
   Local socket address = /192.168.0.5:8888
   Local address = /192.168.0.5
   Local port = 8888
   Need client authentication = false
   Cipher suite = SSL_NULL_WITH_NULL_NULL
   Protocol = NONE
Read=[null]
java.net.SocketException: Connection closed by remote host
    at sun.security.ssl.SSLSocketImpl.checkWrite(Unknown Source)
    at sun.security.ssl.AppOutputStream.write(Unknown Source)
    at sun.nio.cs.StreamEncoder.writeBytes(Unknown Source)
    at sun.nio.cs.StreamEncoder.implFlushBuffer(Unknown Source)
    at sun.nio.cs.StreamEncoder.implFlush(Unknown Source)
    at sun.nio.cs.StreamEncoder.flush(Unknown Source)
    at java.io.OutputStreamWriter.flush(Unknown Source)
    at java.io.BufferedWriter.flush(Unknown Source)
    at HttpsHello.main(HttpsHello.java:43)

但是,Firefox让我在这一点上添加了一个临时例外!!

好的,然后在添加临时异常后,我重新启动了应用程序,并将https://192.168.0.5:8888放入Firefox地址,此时,IT工作,即我得到了“Hello world”网页在Firefox !!

有谁知道为什么会这样?为什么“openssl s_client”工作正常,但是当Firefox从应用程序获得证书作为例外添加证书时,它会随着Firefox的爆炸而增加?

编辑2:

我发表评论说我在我的一台笔记本电脑上工作了,但我仍然没有在我的主开发机上工作。

我正在通过我刚刚进行的测试粘贴SSL调试日志:

http://pastebin.com/faVCjj3a

如果有人能看到可能导致此问题的任何事情,请告诉我们?在完成JKS文件和工作系统的证书后,我做了这个测试。另外,我已经在另一个系统上安装了无限强度策略jar。

...谢谢

编辑3:我想我终于找到了一个似乎有用的例子:

http://www.mybinarylife.net/2012/06/java-ssl-threaded-echo-server.html

我稍微修改了该代码以发送HTTP响应,而不仅仅是回应请求,它似乎甚至可以用于像Firefox这样的浏览器。

看来,使用openssl s_client和浏览器访问服务器的区别在于,当第一个请求发出时,浏览器发现一些问题,如主机名与证书或其他情况不匹配,以及浏览器如Firefox要求例外,存在SSL错误,因此服务器必须能够处理该问题并继续处理请求/连接,而不仅仅是死亡,这个新示例似乎就是这样做。

0 个答案:

没有答案