浅谈基于SSL的Socket通信
客户端认证服务器,即判断当前客户端连接的服务器是否可信
当客户使用SSL向站点服务器发送请求时,服务器向客户端发送一个证书,客户使用已安装的证书,验证服务器身份,然后检查IP地址(主机名)与客户端连接的主机是否匹配。客户生成可以用来对话的私钥(称为会话密钥),然后用服务者的公钥对它进行加密并将它发送到服务者。服务者用自己的私钥解密,然后用该信息和客户端一样的私有会话密钥。通常在这个阶段使用RSA算法。
随后,客户端和服务器端使用私有会话密钥和私钥算法(通常是RC4)进行通信。使用另一个密钥的消息认证码来确保消息的完整性。
使用JSSE实现客户与服务器端安全通信的步骤如下:
1. 建立服务器端密钥库,制作数字证书
(a) 建立服务器端密钥库
(b) 查看密钥库信息
(c) 制作证书
制作证书是从密钥库输出特定别名的证书,保存到证书文件sslsocket.cer
(d) 查看证书文件信息
2. 保存服务器端证书到客户端密钥库,以备客户接收到服务器端证书进行验证
(a) 导入证书
(b) 若希望删除
(c) 查看证书信息
3. 建立服务器端安全的Socket对象
4. 建立客户与服务器端连接的Socket对象
客户端认证服务器,即判断当前客户端连接的服务器是否可信
当客户使用SSL向站点服务器发送请求时,服务器向客户端发送一个证书,客户使用已安装的证书,验证服务器身份,然后检查IP地址(主机名)与客户端连接的主机是否匹配。客户生成可以用来对话的私钥(称为会话密钥),然后用服务者的公钥对它进行加密并将它发送到服务者。服务者用自己的私钥解密,然后用该信息和客户端一样的私有会话密钥。通常在这个阶段使用RSA算法。
随后,客户端和服务器端使用私有会话密钥和私钥算法(通常是RC4)进行通信。使用另一个密钥的消息认证码来确保消息的完整性。
使用JSSE实现客户与服务器端安全通信的步骤如下:
1. 建立服务器端密钥库,制作数字证书
(a) 建立服务器端密钥库
- keytool.exe -genkeypair -v -alias sslsocket -keyalg RSA -keystore e:\keytool\sslsocket.keystore
- 输入keystore密码:
- 再次输入新密码:
- 您的名字与姓氏是什么?
- [Unknown]: lcl
- 您的组织单位名称是什么?
- [Unknown]: hansky
- 您的组织名称是什么?
- [Unknown]: sts
- 您所在的城市或区域名称是什么?
- [Unknown]: bj
- 您所在的州或省份名称是什么?
- [Unknown]: bj
- 该单位的两字母国家代码是什么
- [Unknown]: zh
- CN=lcl, OU=hansky, O=sts, L=bj, ST=bj, C=zh 正确吗?
- [否]: y
- 正在为以下对象生成 1,024 位 RSA 密钥对和自签名证书 (SHA1withRSA)(有效期为 90 天):
- CN=lcl, OU=hansky, O=sts, L=bj, ST=bj, C=zh
- 输入<sslsocket>的主密码
- (如果和 keystore 密码相同,按回车):
- [正在存储 e:\keytool\sslsocket.keystore]
(b) 查看密钥库信息
- keytool.exe -list -v -alias sslsocket -keystore e:\keytool\sslsocket.keystore
(c) 制作证书
制作证书是从密钥库输出特定别名的证书,保存到证书文件sslsocket.cer
- keytool.exe -exportcert -v -alias sslsocket -file e:\keytool\sslsocket.cer -keystore e:\keytool\sslsocket.keystore
- 输入keystore密码:
- 保存在文件中的认证 <e:\keytool\sslsocket.cer>
(d) 查看证书文件信息
- keytool.exe -printcert -v -file e:\keytool\sslsocket.cer
2. 保存服务器端证书到客户端密钥库,以备客户接收到服务器端证书进行验证
(a) 导入证书
- keytool.exe -importcert -v -alias sslsocketcer -file e:\keytool\sslsocket.cer -keystore e:\keytool\sslclient.keystore
- 输入keystore密码:
- 所有者:CN=lcl, OU=hansky, O=sts, L=bj, ST=bj, C=zh
- 签发人:CN=lcl, OU=hansky, O=sts, L=bj, ST=bj, C=zh
- 序列号:4ce5e012
- 有效期: Fri Nov 19 10:25:22 CST 2010 至Thu Feb 17 10:25:22 CST 2011
- 证书指纹:
- MD5:A3:8E:D8:83:4B:FC:12:30:36:0F:E3:F8:3C:EB:CE:74
- SHA1:E3:B8:FB:D3:98:FB:FB:63:D8:BC:A9:F9:AA:F4:FE:8A:54:CC:B6:4B
- 签名算法名称:SHA1withRSA
- 版本: 3
- 信任这个认证? [否]: y
- 认证已添加至keystore中
- [正在存储 e:\keytool\sslclient.keystore]
(b) 若希望删除
- keytool.exe -delete -alias sslsocketcer -keystore e:\keytool\sslclient.keystore
(c) 查看证书信息
- keytool.exe -list -v -keystore e:\keytool\sslclient.keystore
3. 建立服务器端安全的Socket对象
- public class TestSSLSocketServer {
- private static String path = "e:\\keytool\\sslsocket.keystore";
- private static char[] password = "aaaaaaa".toCharArray();
- /**
- * @param args
- */
- public static void main(String[] args) {
- boolean flag = true;
- SSLContext context = null;
- try {
- KeyStore ks = KeyStore.getInstance("JKS");
- ks.load(new FileInputStream(path), password);
- KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
- kmf.init(ks, password);
- KeyManager[] km = kmf.getKeyManagers();
- context = SSLContext.getInstance("SSL");
- context.init(km, null, null);
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (KeyStoreException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- } catch (NoSuchAlgorithmException e) {
- e.printStackTrace();
- } catch (CertificateException e) {
- e.printStackTrace();
- } catch (UnrecoverableKeyException e) {
- e.printStackTrace();
- } catch (KeyManagementException e) {
- e.printStackTrace();
- }
- SSLServerSocketFactory ssf = (SSLServerSocketFactory) context.getServerSocketFactory();
- try {
- SSLServerSocket ss = (SSLServerSocket) ssf.createServerSocket(8000);
- System.out.println("等待客户点连接。。。");
- while (flag) {
- Socket s = ss.accept();
- System.out.println("接收到客户端连接");
- ObjectOutputStream os = new ObjectOutputStream(s.getOutputStream());
- os.writeObject("echo : Hello");
- os.flush();
- os.close();
- System.out.println();
- s.close();
- }
- ss.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
4. 建立客户与服务器端连接的Socket对象
- public class TestSSLSocketClient {
- private static String path = "e:\\keytool\\sslclient.keystore";
- private static char[] password = "aaaaaaa".toCharArray();
- /**
- * @param args
- */
- public static void main(String[] args) {
- SSLContext context = null;
- try {
- KeyStore ts = KeyStore.getInstance("JKS");
- ts.load(new FileInputStream(path), password);
- TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
- tmf.init(ts);
- TrustManager [] tm = tmf.getTrustManagers();
- context = SSLContext.getInstance("SSL");
- context.init(null, tm, null);
- } catch (...... e) { //省略捕获的异常信息
- e.printStackTrace();
- }
- SSLSocketFactory ssf = context.getSocketFactory();
- try {
- SSLSocket ss = (SSLSocket) ssf.createSocket("localhost", 8000);
- System.out.println("客户端就绪。");
- ObjectInputStream br = new ObjectInputStream(ss.getInputStream());
- try {
- System.out.println(br.readObject());
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- br.close();
- ss.close();
- System.out.println("客户端测试ok");
- } catch (UnknownHostException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }