SSL通道能解决用户验证,指纹防篡改,数据加密。 用户验证通过双方的证书链来进行, 防篡改有证书的数字签名,数据加密则由SSL握手协商后的对称密码来对socket包进行加密。
SSL双向验证中,1)客户端需要提供自己的证书供服务器端进行验证。2)服务器端用客户端的证书中的公钥对握手数据加密,客户端需要用自己的密钥来解密握手数据。3)握手中需要产生随机数。 所以JDK中的SSLContext中的初始化方法init中需要这三个参数,其声明方法为
init(KeyManager[] km, TrustManager[] tm, SecureRandom random) ,
以下为样例,我们这里不打算从JDK的keytool建立的库中取证书,只是直接从一个已知的字符串中拿证书,所以直接实现一个简单的TrustManager和KeyManager:
sslcontext = SSLContext.getInstance("SSL"); sslcontext.init(new KeyManager[] {new SimpleKeyManager(privateKey, x509selfCertChain)} , new TrustManager[] {new SimpleTrustManager(x509TrustedCert)} , new SecureRandom ());
SimpleKeyManager实现了X509KeyManager接口,保存自己的证书内容和私钥。
SimpleTrustManager实现了TrustManager接口,保存了客户端信任的证书。
init后SSLContext初始化完成,此时可以调用SSLContext.getSocketFactory()取得SSLSocketFactory实例。然后用取到的factory来建立SSLSocket连接,当然,还需要提供Socket对象,host地址,host端口:
(SSLSocket) sslssFactory.createSocket(Socket s, String host, int port, boolean autoClose);
得到了SSLSocket之后的操作就跟普通socket一样了,socket.getOutputStream()
SSLSocket有几个选项设置SSL连接建立时的设置,如配置服务器模式或客户端模式,以下是较有用的几个:
SSLSocket.setEnabledCipherSuites( new String[]{"SSL_RSA_WITH_RC4_128_MD5" });
SSLSocket支持的密码套件。
SSLSocket.setEnableSessionCreation( true );
新的SSL可以此socket建立。
SSLSocket.setNeedClientAuth( true );
是否要求客户端身份验证,既校验证书。
SSLSocket.setUseClientMode( false );
握手时使用什么模式(客户端/服务器)。