KeyStore.load(InputStream stream,char [] password);我如何知道客户端的密码?

时间:2014-10-04 19:33:51

标签: java ssl certificate

我知道要加载要使用的证书,我需要调用KeyStore.load(InputStream, char[]);。如果需要密码,如何在客户端加载证书?在连接到Google时我不需要这个,但我想使用信任管理器来验证Google证书。我也无法创建SSLServerSocket并在不加载证书的情况下连接到它。
编辑:已添加代码:

package testing;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class SSLClientTest {
    public static void main(String[] args) {
        int port = 443;
        String host = "google.com";

        try {

            SSLContext sc = SSLContext.getInstance("TLSv1.2");
            KeyStore ks = KeyStore.getInstance("JKS");
            InputStream ksIs = new FileInputStream("securecert.certificate");
            try {
                ks.load(ksIs, "pwdpwdpwd".toCharArray());
            } finally {
                if (ksIs != null) {
                    ksIs.close();
                }
            }
            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
            kmf.init(ks, "pwdpwdpwd".toCharArray());
            sc.init(kmf.getKeyManagers(),
                    new TrustManager[] { new MyTrustManager() }, null);

            SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory
                    .getDefault();
            SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
            socket.startHandshake();
            BufferedReader in = new BufferedReader(new InputStreamReader(
                    socket.getInputStream()));
            System.out.println(in.readLine());
            in.close();
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static final class MyTrustManager implements X509TrustManager {

        @Override
        public void checkClientTrusted(X509Certificate[] arg0, String arg1)
                throws CertificateException {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1)
                throws CertificateException {
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[] {};
        }
    }
}

请注意,我必须加载证书,securecert.certificate,代码为ks.load(InputStream,char []);我当然知道密码,但如果我不知道怎么办?那我怎么能用信任管理器验证证书呢?这段代码只是锁定。请回答。谢谢!

1 个答案:

答案 0 :(得分:5)

似乎您需要通过SSL进行客户端身份验证,并且您希望让用户输入其keystore的密码。根据您的解释,我认为每个安装的客户端都有自己的keystore来自本地路径(如果不是问题有无意义,因为如果keystore始终相同,则不需要传递不同的每次密码...但是如果是这种情况你要检查这个客户端是否安全。

因此,要让用户输入密码,您可以以不同的方式实例化keystore,而不是使用KeyStore.getInstance(InputStream, Char[]),您可以使用KeyStore.Builder.newInstanceKeyStore.CallbackHandlerProtection方法,你必须创建一个实现javax.security.auth.callback.CallbackHandler的类,这个类必须覆盖handle()方法,例如使用swing或awt面板让用户引入密码。下面我将向您展示一些示例代码,以指导您完成以下步骤:

加载密钥库

import java.io.File;
import java.security.KeyStore;
import java.security.Provider;
import java.util.Enumeration;

public class KeyStoreCallbackSample {

    public static void main(String args[]) throws Exception {
        // instantiate a keystore to get the provider for specific type
        KeyStore ks = KeyStore.getInstance("JKS");

        // create the callback handler to get the password
        KeyStore.CallbackHandlerProtection cbhp = new KeyStore.CallbackHandlerProtection(new YourImplementationCallbackHander());
        // create the builder passing keystoreType, provider, keystore file, and callbackhandler
        KeyStore.Builder builder = KeyStore.Builder.newInstance("JKS", ks.getProvider(), new File("/path/YourKeyStore.jks"), cbhp);
        // create the keystore
        ks = builder.getKeyStore();

        // print the keystores alias to check if all it's load correctly
        Enumeration<String> aliases = ks.aliases();
        while(aliases.hasMoreElements()){
            System.out.println(aliases.nextElement());
        }       
    }
}   

CallbackHandler实现

import java.io.IOException;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

/**
 * PIN handler for keystores
 */
public class PinInputHandler implements CallbackHandler {

    private char[] lastPassword;

    public PinInputHandler(){}

    // implement this method to handle the callback
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        for (Callback cb : callbacks) {
            if (cb instanceof javax.security.auth.callback.PasswordCallback) {
                javax.security.auth.callback.PasswordCallback pcb = (javax.security.auth.callback.PasswordCallback) cb;
                try {
                    this.lastPassword = // HERE YOUR SWING OR AWT OR ANOTHER WAY TO GET THE PASSWORD FROM THE CLIENT
                } catch (Exception e) {}
                pcb.setPassword(this.lastPassword);
            }
        }
    }
}

如果您需要更多信息,可以访问KeyStoreKeyStore.BuilderKeyStore.CallbackHandlerProtectionCallbackHandler文档。

希望这有帮助,