`

certificate 学习

阅读更多
  前面简单的学习了证书的一些概念。继续学习证书的相关知识及其应用。
  提到证书的应用,可以在输入的地址栏看到https,亦http+SSL/TLS。https在http上多了一个安全性。
  当我们创建好证书,并且在服务器端配置好后,输入https的URL,此时浏览器会为我们完成SSL/TLS握手协议。
  SSL/TLS握手协议分为3次,亦三次握手。
  第一次:客户端浏览器会产生随机数RNC,然后发送SSL信息,算法信息,随机数RNC给服务端。服务端也产生随机数RNC,然后发送SSL信息,算法信息,随机数RNS给客户端,服务端证书,客户端证书请求(可有)。 --算法协商
  第二次:客户端验证证书。若有客户端证书请求,客户端会发送证书给服务器,服务器验证。 --身份验证
  第三次:客户端产生随机数PMS,使用服务端公钥加密随机数PMS,发送随机数PMS加密信息。服务端用私钥解密,获得PMS。然后双方使用随机数RNC,RNS,和PMS建立主密钥MS。主密钥是对称密钥。主密钥生成后,双方会用主密钥构建会话,通知终止握手。 --确定密钥
  握手完后,就使用主密钥加密,解密信息进行通信了,证书在这里的作用就是确认你访问的地址可靠性。可以在这篇文章更加了解握手的内容http://www.infoq.com/cn/articles/HTTPS-Connection-Jeff-Moser。
  开始总有一个疑问,既然公钥,私钥可以加密解密,为什么还要弄一个对称密钥出来做加密,解密。查下资料,人家说非对称密钥加密,解密效率低,对称密钥效率高一些,具体怎么高就要去把数学学好了,呵呵,就这样知道就有了。

  接下来看一下代码是如何实现。我们的代码是运行在容器当中,连接主要靠容器做的,默认情况下都是http开头。若要https开头,就要在容器里面配置一下。我就讲下tomcat的配置。
  tomcat负责连接的是connector,到tomcat的conf目录下打开server.xml文件,找到connector这一块,配置https:
<Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true" maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"     keystoreFile="conf/liu.keystore" keystorePass="123456"/>

https默认端口443,keystorefile指定了密钥库,clientAuth指客户端证书请求,默认false。
   配置完后,你的地址就是使用https开头,并且访问该地址就要通过SSL/TSL协议了。
  
  问题:我开始配置的时候,属性protocol="HTTP/1.1",这是会报错,说tomcat not find a matching property。我上面配置NIO,当然也可以配置成BIO。
  
  浏览器帮我们做了SSL/TLS的功能,客户端用程序访问服务器,是如何做的呢?
  那就要用到HttpsURLConnection和SSLSocketFactory这二个类了。
  HttpsURLConnection用于建立连接,SSLSocketFactory做验证。
 
 
URL url = new URL("httpsUrl");
HttpsURLConnection httpsConn = (HttpsURLConnection) url
					.openConnection();
SSLClientSocket client = new SSLClientSocket();
SSLSocketFactory sslSocketFactory = client.getFactoryNoPath();
httpsConn.setSSLSocketFactory(sslSocketFactory);
httpsConn.getInputStream();


public SSLSocketFactory getFactoryNoPath(){
		 SSLContext context = null;
	        try {
	        	X509TrustManager tm = new X509TrustManager() {
	                public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {}
	                public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {}
	                public X509Certificate[] getAcceptedIssuers() {
	                    return null;
	                }
	            };
	        	context = SSLContext.getInstance("SSL");
	            context.init(null, new TrustManager[] {tm}, null);
	        } catch (KeyManagementException ex) {
	            Logger.getLogger(SSLClientSocket.class.getName()).log(Level.SEVERE, null, ex);
	        }catch (NoSuchAlgorithmException ex) {
	            Logger.getLogger(SSLClientSocket.class.getName()).log(Level.SEVERE, null, ex);
	        }
	        SSLSocketFactory ssf = context.getSocketFactory();
	        return ssf;
	}


步骤很简单,通过URL获得HttpsURLConnection,然后设置一下SSLSocketFactory。SSLClientSocket是自己以前写的,用于获取SSLSocketFactory,这一个socketFactory的并没有做验证服务器证书操作。
开始的时候一直一个错误的理解,认为客户端这边已经得到服务器端证书,而且要验证的话必须给服务端证书,而且写在getAcceptedIssuers里。
在客户端,在checkServerTrusted里面,做服务端证书验证。在服务端,在checkClientTrusted里面做客户端证书验证。

在看一下服务器和客户端都使用程序通信,怎么实现SSL通信
客户端
public void clientSocket(String path) {
        SSLContext context = null;
        try {
            KeyTool keytool = new KeyTool();
            KeyStore keyStore = keytool.getKeyStore(path);
            X509Certificate[] x509 = new X509Certificate[]{(X509Certificate)keytool.getCertificate(keyStore, "serverkey")};
            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
            tmf.init(keyStore);
            TrustManager[] tm = tmf.getTrustManagers();
            context = SSLContext.getInstance("SSL");
            context.init(null, new TrustManager[]{new SSLTrustManager(x509)}, null);
            //context.init(null,tm, null);
        } catch (KeyManagementException ex) {
            Logger.getLogger(SSLClientSocket.class.getName()).log(Level.SEVERE, null, ex);
        } catch (KeyStoreException ex) {
            Logger.getLogger(SSLClientSocket.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(SSLClientSocket.class.getName()).log(Level.SEVERE, null, ex);
        }
        SSLSocketFactory ssf = context.getSocketFactory();
        try {
            SSLSocket ss = (SSLSocket) ssf.createSocket("localhost", 8000);
            System.out.println("customer already");
            ObjectInputStream os = new ObjectInputStream(ss.getInputStream());
            System.out.println(os.readObject());
            os.close();
            ss.close();
            System.out.println("ok");

        } catch (ClassNotFoundException ex) {
            Logger.getLogger(SSLClientSocket.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(SSLClientSocket.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

可以根据该方法获取服务器证书
 Certificate[] aCerts = ss.getSession().getPeerCertificates();


服务端

public void sslServerSocket(String path) {
        boolean flag = true;
        SSLContext context = null;
        try {
            KeyTool keytool = new KeyTool();
            KeyStore keyStore = keytool.getKeyStore(path);
            PrivateKey pk = keytool.getPrivateKey(keyStore, "serverkey");
            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
            kmf.init(keyStore, "123456".toCharArray());
            X509Certificate[] x509 = new X509Certificate[]{(X509Certificate)keytool.getCertificate(keyStore, "serverkey")};
            KeyManager[] km = kmf.getKeyManagers();
//            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
//            tmf.init(keyStore);
//            TrustManager[] tm = tmf.getTrustManagers();
            context = SSLContext.getInstance("SSL");
            context.init(new KeyManager[]{new SSLKeyManager(pk,x509)}, null, null);
            //context.init(km, null, null);
        } catch (KeyManagementException ex) {
            Logger.getLogger(SSLServerSockets.class.getName()).log(Level.SEVERE, null, ex);
        } catch (KeyStoreException ex) {
            Logger.getLogger(SSLServerSockets.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnrecoverableKeyException ex) {
            Logger.getLogger(SSLServerSockets.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(SSLServerSockets.class.getName()).log(Level.SEVERE, null, ex);
        }

        SSLServerSocketFactory ssf = context.getServerSocketFactory();
        try {
            SSLServerSocket ss = (SSLServerSocket) ssf.createServerSocket(8000);
            System.out.println("wait for customer connect");
            while (flag) {
                Socket s = ss.accept();
                System.out.println("accept customer connecting");
                ObjectOutputStream os = new ObjectOutputStream(s.getOutputStream());
                os.writeObject("echo: hello");
                os.flush();
                os.close();
                System.out.println();
                s.close();
            }
            ss.close();
        } catch (IOException ex) {
            Logger.getLogger(SSLServerSockets.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

我代码里面初始化KeyManager/TrustManager用了二种方式,一种是从factory里面创建,另一种是直接构建他们的实现类。keystore我初学的时候已经写了怎么获得,keytool是自己写的类。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics