使用"单面"创建纯Java HTTPS服务器认证?

时间:2014-07-25 15:46:28

标签: java https

我可以轻松地创建一个我需要的HTTP纯Java服务器。但是,像这样的HTTPS服务器:

package httpstest;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsServer;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

public class HttpsTest {

    public static void main(String[] args) throws Exception {
        HttpsServer server = HttpsServer.create(new InetSocketAddress(8000), 0);
        server.setHttpsConfigurator(new HttpsConfigurator(createSSLContext()));
        server.createContext("/test", new TestHandler());
        server.setExecutor(null); // creates a default executor
        server.start();
    }

    private static SSLContext createSSLContext() throws Exception {
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        InputStream is = new FileInputStream("server.crt");
        InputStream caInput = new BufferedInputStream(is);
        Certificate ca = cf.generateCertificate(caInput);
        caInput.close();

        // Create a KeyStore containing our trusted CAs
        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);

        // Create a TrustManager that trusts the CAs in our KeyStore
        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);

        // Create an SSLContext that uses our TrustManager
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, tmf.getTrustManagers(), null);

        return context;
    }

    static class TestHandler implements HttpHandler {

        @Override
        public void handle(HttpExchange t) throws IOException {
            String response = "Successfully connected!";
            t.sendResponseHeaders(200, response.length());
            OutputStream os = t.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }
}

将编译并运行服务器端而没有错误,但会从浏览器中产生SSL错误。似乎服务器期望浏览器具有相同的证书。我希望任何浏览器都通过HTTPS连接到它而没有安装证书(就像有人会连接到https://www.google.com

3 个答案:

答案 0 :(得分:1)

有可能。以下是关键代码:

SSLContext sslContext = SSLContext.getInstance("TLS");
char[] keystorePassword = "password".toCharArray();
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("filename.jks"), keystorePassword);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, keystorePassword);
sslContext.init(kmf.getKeyManagers(), null, null);
HttpsConfigurator configurator = new HttpsConfigurator(sslContext);

答案 1 :(得分:0)

当您是服务器时,您需要在KeyManager中安装私有证书。 TrustManager用于与私有客户端证书相对应的公共证书。显然,如果您不希望浏览器投诉,则需要来自可信CA的私有证书。

答案 2 :(得分:0)

当您使用HTTPS连接到Google时,您的浏览器中的证书已经可用,因为它是由受信任的CA签名的证书。

要执行您的意图,您必须使用已签名的证书(您需要为此付费或某些人使用来自StarCom的免费签名证书,但我不确定最后一个)