Posted on 2007-07-20 21:31 
kooyee 阅读(980) 
评论(0)  编辑  收藏  所属分类: 
SSL  
			 
			
		 
		概念 
JAVA使用keystore文件来存储所有KEY,keystore文件可以存放多个KEY,访问它需要密码。
下面我介绍下如何将用OpenSSL做自签名的证书一文中介绍的OpenSSL产生的KEY与JAVA的KEY转换后使用,从而达到JAVA与OpenSSL通信的目的。
用OpenSSL生成CA根证书,即(P1,V1)
此步骤参见用OpenSSL做自签名的证书一文
在JAVA环境下生成自己的KEY,即(P2,V2)
keytool -genkey -alias clientapp -keystore mycerts
注意:这里会提示输入访问keystore的密码,以及组织、城市、省份,一定要与CA根证书的一致,否则不能被CA签名。
从keystore中导出public key,即P2
keytool -keystore mycerts -certreq -alias clientapp -file clientapp.crs
用CA根证书为这个public key进行签名,即用V1给P2加密
openssl ca -out clientapp.pem -config ./openssl.cnf -infiles clientapp.crs
 
转换PEM到DER格式
openssl x509 -in clientapp.pem -out clientapp.der -outform DER
导入CA证书,即P1
keytool -keystore mycerts -alias systemca -import -file cacert.pem
导入用户证书,即被V1加密过的P2
keytool -keystore mycerts -alias clientapp -import -file clientapp.der
注意:这里一定要先导入CA证书再导入用户证书,否则会报错。
现在我们就生成了JAVA服务器使用的所有KEY了,在程序中将mycerts这个keystore导入就可以了。
如果客户端是使用OpenSSL的程序,那么用CA证书cacert.pem就能正常通信了,如果也是JAVA程序,那么我们需要将CA证书也转换成keystore:
keytool -import -keystore clikeystore -import -trustcacerts -file cacert.pem
生成的clikeystore供JAVA客户端使用,就能通信。
再附上SVR和CLI的JAVA程序,我已经用上面的KEY都测试通过:
SVR端:
 import  java.io. * ;
 import  java.io. * ;
 import  java.net. * ;
 import  java.net. * ;
 import  com.sun.net.ssl.KeyManagerFactory;
 import  com.sun.net.ssl.KeyManagerFactory;
 import  com.sun.net.ssl.KeyManager;
 import  com.sun.net.ssl.KeyManager;
 import  com.sun.net.ssl.TrustManagerFactory;
 import  com.sun.net.ssl.TrustManagerFactory;
 import  com.sun.net.ssl.TrustManager;
 import  com.sun.net.ssl.TrustManager;
 import  com.sun.net.ssl.SSLContext;
 import  com.sun.net.ssl.SSLContext;
 import  javax.net.ServerSocketFactory;
 import  javax.net.ServerSocketFactory;
 import  java.security.KeyStore;
 import  java.security.KeyStore;


 public   class  svr  implements  Runnable
 public   class  svr  implements  Runnable  {
 {
 
  
 public   static   final   int  PORT  =   5555 ;
   public   static   final   int  PORT  =   5555 ;
 public   static   final  String HOST  =   " localhost " ;
   public   static   final  String HOST  =   " localhost " ;
 public   static   final  String QUESTION  =   " Knock, knock. " ;
   public   static   final  String QUESTION  =   " Knock, knock. " ;
 public   static   final  String ANSWER  =   " Who's there? " ;
   public   static   final  String ANSWER  =   " Who's there? " ;

 //  The new constants that are used during setup.
   //  The new constants that are used during setup. 
 public   static   final  String KEYSTORE_FILE  =   " mycerts " ; // "server_keystore";
    public   static   final  String KEYSTORE_FILE  =   " mycerts " ; // "server_keystore"; 
 public   static   final  String ALGORITHM  =   " sunx509 " ;
    public   static   final  String ALGORITHM  =   " sunx509 " ;
 public   static   final  String PASSWORD  =   " churchillobjects " ;
   public   static   final  String PASSWORD  =   " churchillobjects " ;
 
  

 public   static   void  main(String[] args)
   public   static   void  main(String[] args)  {
 {
 new  Thread( new  svr()).start();
     new  Thread( new  svr()).start();
 }
  } 
 
  

 public   void  run()
   public   void  run()  {
 {
 ServerSocket ss  =   null ;
    ServerSocket ss  =   null ;

 try
     try    {
 {

 //  Local references used for clarity. Their presence
       //  Local references used for clarity. Their presence
 //  here is part of the reason we need to import
       //  here is part of the reason we need to import
 //  so many classes.
       //  so many classes. 
 KeyManagerFactory kmf;
       KeyManagerFactory kmf;
 KeyManager[] km;
      KeyManager[] km;
 KeyStore ks;
      KeyStore ks;
 TrustManagerFactory tmf;
      TrustManagerFactory tmf;
 TrustManager[] tm;
      TrustManager[] tm;
 SSLContext sslc;
      SSLContext sslc;
 
      
 //  Create a keystore that will read the JKS (Java KeyStore)
       //  Create a keystore that will read the JKS (Java KeyStore)
 //  file format which was created by the keytool utility.
       //  file format which was created by the keytool utility. 
 ks  =  KeyStore.getInstance( " JKS " );
       ks  =  KeyStore.getInstance( " JKS " );
 
      
 //  Load the keystore object with the binary keystore file and
       //  Load the keystore object with the binary keystore file and
 //  a byte array representing its password.
       //  a byte array representing its password. 
 ks.load( new  FileInputStream(KEYSTORE_FILE), PASSWORD.toCharArray());
       ks.load( new  FileInputStream(KEYSTORE_FILE), PASSWORD.toCharArray());
 
      
 //  Gives us a factory for key managers that will let
       //  Gives us a factory for key managers that will let
 //  us handle the asymetric keys we created earlier.
       //  us handle the asymetric keys we created earlier. 
 kmf  =  KeyManagerFactory.getInstance(ALGORITHM);
       kmf  =  KeyManagerFactory.getInstance(ALGORITHM);

 //  Initialize the key manager factory with the keystore object,
       //  Initialize the key manager factory with the keystore object,
 //  again using the same password for security since it is going to
       //  again using the same password for security since it is going to
 //  access the private key.
       //  access the private key. 
 kmf.init(ks, PASSWORD.toCharArray());
       kmf.init(ks, PASSWORD.toCharArray());
 
      
 //  Now we can get the key managers from the factory, since it knows
       //  Now we can get the key managers from the factory, since it knows
 //  what type we are using now.
       //  what type we are using now. 
 km  =  kmf.getKeyManagers();
       km  =  kmf.getKeyManagers();
 
      
 //  Next, create a trust manager factory using the same algorithm.
       //  Next, create a trust manager factory using the same algorithm.
 //  This is to avoid using the certificates in cacerts that
       //  This is to avoid using the certificates in cacerts that
 //  represent an authentication security risk.
       //  represent an authentication security risk. 
 tmf  =  TrustManagerFactory.getInstance(ALGORITHM);
       tmf  =  TrustManagerFactory.getInstance(ALGORITHM);
 
      
 //
       //   then initialize it with the keystore object. This time we don't
then initialize it with the keystore object. This time we don't
 //  need the keystore password. This is because trusted certificates
       //  need the keystore password. This is because trusted certificates
 //  are not a sensitive element in the keystore, unlike the
       //  are not a sensitive element in the keystore, unlike the
 //  private keys.
       //  private keys. 
 tmf.init(ks);
       tmf.init(ks);
 
      
 //  Once that's initialized, get the trust managers from the factory.
       //  Once that's initialized, get the trust managers from the factory. 
 tm  =  tmf.getTrustManagers();
       tm  =  tmf.getTrustManagers();
 
      
 //  Almost done, we need a context object that will get our
       //  Almost done, we need a context object that will get our
 //  server socket factory. We specify TLS to indicate that we will
       //  server socket factory. We specify TLS to indicate that we will
 //  need a server socket factory that supports SSL.
       //  need a server socket factory that supports SSL. 
 sslc  =  SSLContext.getInstance( " TLS " );
       sslc  =  SSLContext.getInstance( " TLS " );
 
      
 //  Initialize the context object with the key managers and trust
       //  Initialize the context object with the key managers and trust
 //  managers we got earlier. The third parameter is an optional
       //  managers we got earlier. The third parameter is an optional
 //  SecureRandom object. By passing in null, we are letting the
       //  SecureRandom object. By passing in null, we are letting the
 //  context object create its own.
       //  context object create its own. 
 sslc.init(km, tm,  null );
       sslc.init(km, tm,  null );
 
      
 //  Finally, we get the ordinary-looking server socket factory
       //  Finally, we get the ordinary-looking server socket factory
 //  from the context object.
       //  from the context object. 
 ServerSocketFactory ssf  =  sslc.getServerSocketFactory();
       ServerSocketFactory ssf  =  sslc.getServerSocketFactory();
 
      
 //  From the factory, we simply ask for an ordinary-looking
       //  From the factory, we simply ask for an ordinary-looking
 //  server socket on the port we wish.
       //  server socket on the port we wish. 
 ss  =  ssf.createServerSocket(PORT);
       ss  =  ssf.createServerSocket(PORT);

 listen(ss);
      listen(ss);
 }
    } 
 
  catch (Exception e)
     catch (Exception e)  {
 {
 e.printStackTrace();
      e.printStackTrace();
 }
    } 
 
  finally
     finally  {
 {

 if (ss != null )
       if (ss != null )  {
 {

 try
         try  {
 {
 ss.close();
          ss.close();
 }
        } 
 
  catch (IOException e)
         catch (IOException e)  {
 {
 //  oh, well
           //  oh, well 
 
 }
         } 
 }
      } 
 System.exit( 0 );
      System.exit( 0 );
 }
    } 
 }
  } 
 
  

 static   void  listen(ServerSocket ss)  throws  Exception
   static   void  listen(ServerSocket ss)  throws  Exception  {
 {
 System.out.println( " Ready for connections. " );
    System.out.println( " Ready for connections. " );

 while ( true )
     while ( true )  {
 {
 Socket s  =  ss.accept();
      Socket s  =  ss.accept();
 BufferedWriter bw  =   new  BufferedWriter(
      BufferedWriter bw  =   new  BufferedWriter(
 new  OutputStreamWriter(s.getOutputStream()));
         new  OutputStreamWriter(s.getOutputStream()));
 BufferedReader br  =   new  BufferedReader(
      BufferedReader br  =   new  BufferedReader(
 new  InputStreamReader(s.getInputStream()));
         new  InputStreamReader(s.getInputStream()));
 String q  =  br.readLine();
      String q  =  br.readLine();

 if ( ! QUESTION.equals(q))
       if ( ! QUESTION.equals(q))  {
 {
 throw   new  RuntimeException( " Wrong question: \ ""  + q +  " \ "" );
         throw   new  RuntimeException( " Wrong question: \ ""  + q +  " \ "" );
 }
      } 
 System.out.println( " Question: \ ""  + q +  " \ "" );
      System.out.println( " Question: \ ""  + q +  " \ "" );
 bw.write(ANSWER + " \n " );
      bw.write(ANSWER + " \n " );
 bw.flush();
      bw.flush();
 s.close();
      s.close();
 }
    } 
 }
  } 
 }
} 
CLI端程序:
 import  java.io. * ;
 import  java.io. * ;
 import  java.net. * ;
 import  java.net. * ;
 import  com.sun.net.ssl.KeyManagerFactory;
 import  com.sun.net.ssl.KeyManagerFactory;
 import  com.sun.net.ssl.TrustManagerFactory;
 import  com.sun.net.ssl.TrustManagerFactory;
 import  com.sun.net.ssl.SSLContext;
 import  com.sun.net.ssl.SSLContext;
 import  java.security.KeyStore;
 import  java.security.KeyStore;
 import  javax.net.SocketFactory;
 import  javax.net.SocketFactory;


 public   class  cli  implements  Runnable
 public   class  cli  implements  Runnable  {
 {
 
  
 public   static   final   int  PORT  =   5555 ;
   public   static   final   int  PORT  =   5555 ;
 public   static   final  String HOST  =   " localhost " ;
   public   static   final  String HOST  =   " localhost " ;
 public   static   final  String KEYSTORE_FILE  =   " clikeystore " ; // "client_keystore";
   public   static   final  String KEYSTORE_FILE  =   " clikeystore " ; // "client_keystore"; 
 public   static   final  String ALGORITHM  =   " sunx509 " ;
    public   static   final  String ALGORITHM  =   " sunx509 " ;
 public   static   final  String PASSWORD  =   " churchillobjects " ;
   public   static   final  String PASSWORD  =   " churchillobjects " ;
 public   static   final  String QUESTION  =   " Knock, knock. " ;
   public   static   final  String QUESTION  =   " Knock, knock. " ;
 public   static   final  String ANSWER  =   " Who's there? " ;
   public   static   final  String ANSWER  =   " Who's there? " ;
 
  

 public   static   void  main(String[] args)
   public   static   void  main(String[] args)  {
 {
 new  Thread( new  cli()).start();
     new  Thread( new  cli()).start();
 }
  } 
 
  

 public   void  run()
   public   void  run()  {
 {
 Socket socket  =   null ;
    Socket socket  =   null ;

 try
     try  {
 {
 KeyManagerFactory kmf;
      KeyManagerFactory kmf;
 KeyStore ks;
      KeyStore ks;
 TrustManagerFactory tmf;
      TrustManagerFactory tmf;
 SSLContext sslc;
      SSLContext sslc;

 kmf  =  KeyManagerFactory.getInstance(ALGORITHM);
      kmf  =  KeyManagerFactory.getInstance(ALGORITHM);
 ks  =  KeyStore.getInstance(  " JKS "  );
      ks  =  KeyStore.getInstance(  " JKS "  );
 ks.load( new  FileInputStream(KEYSTORE_FILE), PASSWORD.toCharArray());
      ks.load( new  FileInputStream(KEYSTORE_FILE), PASSWORD.toCharArray());
 kmf.init(ks, PASSWORD.toCharArray());
      kmf.init(ks, PASSWORD.toCharArray());
 tmf  =  TrustManagerFactory.getInstance(ALGORITHM);
      tmf  =  TrustManagerFactory.getInstance(ALGORITHM);
 tmf.init(ks);
      tmf.init(ks);
 sslc  =  SSLContext.getInstance( " TLS " );
      sslc  =  SSLContext.getInstance( " TLS " );
 sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(),  null );
      sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(),  null );

 //  The process is different from here on the client. Instead of
       //  The process is different from here on the client. Instead of
 //  getting a ServerSocketFactory, we ask for a SocketFactory from
       //  getting a ServerSocketFactory, we ask for a SocketFactory from
 //  the SSL context.
       //  the SSL context. 
 SocketFactory sf  =  sslc.getSocketFactory();
       SocketFactory sf  =  sslc.getSocketFactory();

 //  Then we get the socket from the factory and treat it
       //  Then we get the socket from the factory and treat it
 //  as if it were a standard (plain) socket.
       //  as if it were a standard (plain) socket. 
 socket  =  sf.createSocket(HOST, PORT);
       socket  =  sf.createSocket(HOST, PORT);
 
    
 doQuery(socket);
      doQuery(socket);
 }
    } 
 
  catch (Exception e)
     catch (Exception e)  {
 {
 e.printStackTrace();
      e.printStackTrace();
 }
    } 
 
  finally
     finally  {
 {

 if (socket != null )
       if (socket != null )  {
 {

 try
         try  {
 {
 socket.close();
          socket.close();
 }
        } 
 
  catch (IOException e)
         catch (IOException e)  {
 {
 //  oh, well
           //  oh, well 
 
 }
         } 
 }
      } 
 System.exit( 0 );
      System.exit( 0 );
 }
    } 
 }
  } 
 
 
 
  private   void  doQuery(Socket s)  throws  Exception
   private   void  doQuery(Socket s)  throws  Exception  {
 {
 BufferedWriter bw  =   new  BufferedWriter( new  OutputStreamWriter(s.getOutputStream()));
    BufferedWriter bw  =   new  BufferedWriter( new  OutputStreamWriter(s.getOutputStream()));
 BufferedReader br  =   new  BufferedReader( new  InputStreamReader(s.getInputStream()));
    BufferedReader br  =   new  BufferedReader( new  InputStreamReader(s.getInputStream()));
 bw.write(QUESTION + " \n " );
    bw.write(QUESTION + " \n " );
 bw.flush();
    bw.flush();
 String response  =  br.readLine();
    String response  =  br.readLine();

 if ( ! ANSWER.equals(response))
     if ( ! ANSWER.equals(response))  {
 {
 throw   new  RuntimeException( " Wrong answer: \ ""  + response +  " \ "" );
       throw   new  RuntimeException( " Wrong answer: \ ""  + response +  " \ "" );
 }
    } 
 System.out.println( " Got the right answer: \ ""  + response +  " \ "" );
    System.out.println( " Got the right answer: \ ""  + response +  " \ "" );
 }
  } 
 }
}