certificate 学习
程序员文章站
2022-07-14 15:04:43
...
前面简单的学习了证书的一些概念。继续学习证书的相关知识及其应用。
提到证书的应用,可以在输入的地址栏看到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:
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获得HttpsURLConnection,然后设置一下SSLSocketFactory。SSLClientSocket是自己以前写的,用于获取SSLSocketFactory,这一个socketFactory的并没有做验证服务器证书操作。
开始的时候一直一个错误的理解,认为客户端这边已经得到服务器端证书,而且要验证的话必须给服务端证书,而且写在getAcceptedIssuers里。
在客户端,在checkServerTrusted里面,做服务端证书验证。在服务端,在checkClientTrusted里面做客户端证书验证。
在看一下服务器和客户端都使用程序通信,怎么实现SSL通信
客户端
可以根据该方法获取服务器证书
服务端
我代码里面初始化KeyManager/TrustManager用了二种方式,一种是从factory里面创建,另一种是直接构建他们的实现类。keystore我初学的时候已经写了怎么获得,keytool是自己写的类。
提到证书的应用,可以在输入的地址栏看到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是自己写的类。
上一篇: Java通过SSL忽略Certificate访问LDAP服务器
下一篇: 使用keytool工具