分享

在mina中实现TSL/SSL双向认证连接(1)

 昵称2073162 2010-07-07
本文需要读者对mina和SSl原理有一定的了解,所以本文中对mina和SSL的原理,不做详细的介绍。

TSL/SSL双向认证连接:Server端和Client端通信,需要进行授权和身份的验证,即Client只能接受Server的消息,Server只能接受Client的消息。这样就可以在客户机和服务器之间通过TCP/IP协议安全地传输数据。

在mina中实现TSL/SSL双向认证连接,本人目前所知有三种方式:
1.Server端和Client端各自拥有自签名的私有密钥证书,重写的 javax.net.ssl.X509TrustManager接口中的三个方法实现Server端和Client端信认证书。
2.Server端和Client端各自拥有自签名的私有密钥证书,并且互相交换公钥,通过对方公钥互相信认对方证书。
3.Server端和Client端各自拥有可信认的第三方认证机构(CA)签名私有密钥证书,通过CA互相信认对方证书。
以上三种方式,实现复杂度从低到高,灵活度安全性也从低到高。本系列文章将将会从简到难分别介绍三种方式的TSL/SSL双向认证连接。

下面我们介绍第一种实现方式:Server端和Client端各自拥有自签名的私有密钥证书,重写的 javax.net.ssl.X509TrustManager接口中的三个方法实现Server端和Client端信认证书。

首先,创建Server端和Client端各自的私有密钥证书,在这里使用keytool,关于keytool的使用在这里不作详细介绍,请参考它处。

1.创建Server端KeyStore文件serverKeys.jks,包含一个用于服务器的证书 :
引用
keytool -genkey -alias server -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=sundoctor.com, OU=Developer,O=Techstar, L=Beijing, S=Beijing, C=CH" -keypass 123456 -storepass 123456 -keystore serverKeys.jks


2.创建Client端KeyStore文件clientKeys.jks,分别包含用于虚构的通信者 Alice 和 Bob 的证书 :
引用
keytool -genkey -alias alice -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=Aclie, OU=Developer,O=Techstar, L=Beijing, S=Beijing, C=CH" -keypass 123456 -storepass 123456 -keystore clientKeys.jks

keytool -genkey -alias bob -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=Bob, OU=Developer,O=Techstar, L=Beijing, S=Beijing, C=CH" -keypass 123456 -storepass 123456 -keystore clientKeys.jks


其次重写的 javax.net.ssl.X509TrustManager接口中的三个方法实现Server端和Client端信认证书,代码中BogusTrustManagerFactory类有关X509TrustManager实现的片断,具体参考源码
Java代码 复制代码
  1. static final X509TrustManager X509 = new X509TrustManager() {   
  2.   
  3.     /**  
  4.      * 确认和信任将其用于基于身份验证类型的客户端 SSL 身份验证  
  5.      */  
  6.     public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {   
  7.   
  8.         if (x509Certificates == null || x509Certificates.length == 0)   
  9.             throw new IllegalArgumentException("null or zero-length certificate chain");   
  10.         if (s == null || s.length() == 0)   
  11.             throw new IllegalArgumentException("null or zero-length authentication type");   
  12.   
  13.         boolean br = false;   
  14.         Principal principal = null;   
  15.         for (X509Certificate x509Certificate : x509Certificates) {   
  16.             principal = x509Certificate.getSubjectDN();   
  17.             if (principal != null && (StringUtils.contains(principal.getName(), "Alice") || StringUtils.contains(principal.getName(), "Bob"))) {   
  18.                 br = true;   
  19.                 return;   
  20.             }   
  21.         }   
  22.   
  23.         if (!br) {   
  24.             throw new CertificateException("连接认证失败!");   
  25.         }   
  26.     }   
  27.   
  28.     /**  
  29.      * 确认和信任将其用于基于身份验证类型的服务器 SSL 身份验证  
  30.      */  
  31.     public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {   
  32.         if (x509Certificates == null || x509Certificates.length == 0)   
  33.             throw new IllegalArgumentException("null or zero-length certificate chain");   
  34.         if (s == null || s.length() == 0)   
  35.             throw new IllegalArgumentException("null or zero-length authentication type");   
  36.   
  37.         boolean br = false;   
  38.         Principal principal = null;   
  39.         for (X509Certificate x509Certificate : x509Certificates) {   
  40.             principal = x509Certificate.getSubjectDN();   
  41.             if (principal != null && (StringUtils.contains(principal.getName(), "sundoctor.com"))) {   
  42.                 br = true;   
  43.                 return;   
  44.             }   
  45.         }   
  46.   
  47.         if (!br) {   
  48.             throw new CertificateException("连接认证失败!");   
  49.         }   
  50.     }   
  51.   
  52.     public X509Certificate[] getAcceptedIssuers() {   
  53.         return new X509Certificate[0];   
  54.     }   
  55. };  

在这里checkClientTrusted(X509Certificate[] x509Certificates, String s)验证客户端证书,在这里只是简单的验证一下客户端证书CN是否为Alice或Bob, checkServerTrusted(X509Certificate[] x509Certificates, String s)验证服务端证书,这里只是简单的验证一下服务端的CN是否为sundoctor.com。更复杂的验证,大家可以自行实现。

最后是创建服务端和客户端SSLContext工厂类,分别初始化服务端和客户端的SSLContext
Java代码 复制代码
  1. // Initialize the SSLContext to work with our key managers.   
  2. SSLContext sslContext = SSLContext.getInstance(PROTOCOL);   
  3. sslContext.init(getKeyManagers(serverKeys, serverKeysPassword), BogusTrustManagerFactory.X509_MANAGERS, null);  

初始化SSLContext需要KeyManagers和TrustManager,TrustManager参见BogusTrustManagerFactory,使用serverKeys.jks、clientKeys.jks分别构建服务端和客户端KeyManagers
Java代码 复制代码
  1. private static KeyManager[] getKeyManagers(String keysfile, String password) throws GeneralSecurityException,   
  2.         IOException {   
  3.   
  4.     // First, get the default KeyManagerFactory.   
  5.     KeyManagerFactory kmf = KeyManagerFactory.getInstance(KEY_MANAGER_FACTORY_ALGORITHM);   
  6.        
  7.     // Next, set up the TrustStore to use. We need to load the file into   
  8.     // a KeyStore instance.    
  9.     KeyStore ks = KeyStore.getInstance("JKS");   
  10.     InputStream in = BogusSslContextFactory.class.getResourceAsStream(keysfile);   
  11.     ks.load(in, password.toCharArray());   
  12.     in.close();   
  13.   
  14.     // Now we initialise the KeyManagerFactory with this KeyStore      
  15.     kmf.init(ks, password.toCharArray());   
  16.   
  17.     // And now get the TrustManagers   
  18.     return kmf.getKeyManagers();   
  19. }  


服务端(TLSServer)和客户端(TLSClient)测试代码比较简单,具体请参考源码,在这里有一点需要注意的就是在服务端添加加密过滤器 SslFilter时必须设置为:sslFilter.setNeedClientAuth(true),需要验证客户端证书。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多