Posted on 2007-05-11 03:31
kooyee 阅读(636)
评论(1) 编辑 收藏
概念 JAVA使用keystore文件来存储所有KEY,keystore文件可以存放多个KEY,访问它需要密码。下面我介绍下如何将用OpenSSL做自签名的证书一文中介绍的OpenSSL产生的KEY与JAVA的KEY转换后使用,从而达到JAVA与OpenSSL通信的目的。
文章来源:
http://blog.csdn.net/ky5566/archive/2007/05/10/1603531.aspx
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.net. * ;
import com.sun.net.ssl.KeyManagerFactory;
import com.sun.net.ssl.KeyManager;
import com.sun.net.ssl.TrustManagerFactory;
import com.sun.net.ssl.TrustManager;
import com.sun.net.ssl.SSLContext;
import javax.net.ServerSocketFactory;
import java.security.KeyStore;
public class svr implements Runnable {
public static final int PORT = 5555 ;
public static final String HOST = " localhost " ;
public static final String QUESTION = " Knock, knock. " ;
public static final String ANSWER = " Who's there? " ;
// The new constants that are used during setup.
public static final String KEYSTORE_FILE = " mycerts " ; // "server_keystore";
public static final String ALGORITHM = " sunx509 " ;
public static final String PASSWORD = " churchillobjects " ;
public static void main(String[] args) {
new Thread( new svr()).start();
}
public void run() {
ServerSocket ss = null ;
try {
// Local references used for clarity. Their presence
// here is part of the reason we need to import
// so many classes.
KeyManagerFactory kmf;
KeyManager[] km;
KeyStore ks;
TrustManagerFactory tmf;
TrustManager[] tm;
SSLContext sslc;
// Create a keystore that will read the JKS (Java KeyStore)
// file format which was created by the keytool utility.
ks = KeyStore.getInstance( " JKS " );
// Load the keystore object with the binary keystore file and
// a byte array representing its password.
ks.load( new FileInputStream(KEYSTORE_FILE), PASSWORD.toCharArray());
// Gives us a factory for key managers that will let
// us handle the asymetric keys we created earlier.
kmf = KeyManagerFactory.getInstance(ALGORITHM);
// Initialize the key manager factory with the keystore object,
// again using the same password for security since it is going to
// access the private key.
kmf.init(ks, PASSWORD.toCharArray());
// Now we can get the key managers from the factory, since it knows
// what type we are using now.
km = kmf.getKeyManagers();
// Next, create a trust manager factory using the same algorithm.
// This is to avoid using the certificates in cacerts that
// represent an authentication security risk.
tmf = TrustManagerFactory.getInstance(ALGORITHM);
// then initialize it with the keystore object. This time we don't
// need the keystore password. This is because trusted certificates
// are not a sensitive element in the keystore, unlike the
// private keys.
tmf.init(ks);
// Once that's initialized, get the trust managers from the factory.
tm = tmf.getTrustManagers();
// Almost done, we need a context object that will get our
// server socket factory. We specify TLS to indicate that we will
// need a server socket factory that supports SSL.
sslc = SSLContext.getInstance( " TLS " );
// Initialize the context object with the key managers and trust
// managers we got earlier. The third parameter is an optional
// SecureRandom object. By passing in null, we are letting the
// context object create its own.
sslc.init(km, tm, null );
// Finally, we get the ordinary-looking server socket factory
// from the context object.
ServerSocketFactory ssf = sslc.getServerSocketFactory();
// From the factory, we simply ask for an ordinary-looking
// server socket on the port we wish.
ss = ssf.createServerSocket(PORT);
listen(ss);
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (ss != null ) {
try {
ss.close();
}
catch (IOException e) {
// oh, well
}
}
System.exit( 0 );
}
}
static void listen(ServerSocket ss) throws Exception {
System.out.println( " Ready for connections. " );
while ( true ) {
Socket s = ss.accept();
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(s.getOutputStream()));
BufferedReader br = new BufferedReader(
new InputStreamReader(s.getInputStream()));
String q = br.readLine();
if ( ! QUESTION.equals(q)) {
throw new RuntimeException( " Wrong question: \ "" + q + " \ "" );
}
System.out.println( " Question: \ "" + q + " \ "" );
bw.write(ANSWER + " \n " );
bw.flush();
s.close();
}
}
}
CLI端程序:
import java.io. * ;
import java.net. * ;
import com.sun.net.ssl.KeyManagerFactory;
import com.sun.net.ssl.TrustManagerFactory;
import com.sun.net.ssl.SSLContext;
import java.security.KeyStore;
import javax.net.SocketFactory;
public class cli implements Runnable {
public static final int PORT = 5555 ;
public static final String HOST = " localhost " ;
public static final String KEYSTORE_FILE = " clikeystore " ; // "client_keystore";
public static final String ALGORITHM = " sunx509 " ;
public static final String PASSWORD = " churchillobjects " ;
public static final String QUESTION = " Knock, knock. " ;
public static final String ANSWER = " Who's there? " ;
public static void main(String[] args) {
new Thread( new cli()).start();
}
public void run() {
Socket socket = null ;
try {
KeyManagerFactory kmf;
KeyStore ks;
TrustManagerFactory tmf;
SSLContext sslc;
kmf = KeyManagerFactory.getInstance(ALGORITHM);
ks = KeyStore.getInstance( " JKS " );
ks.load( new FileInputStream(KEYSTORE_FILE), PASSWORD.toCharArray());
kmf.init(ks, PASSWORD.toCharArray());
tmf = TrustManagerFactory.getInstance(ALGORITHM);
tmf.init(ks);
sslc = SSLContext.getInstance( " TLS " );
sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null );
// The process is different from here on the client. Instead of
// getting a ServerSocketFactory, we ask for a SocketFactory from
// the SSL context.
SocketFactory sf = sslc.getSocketFactory();
// Then we get the socket from the factory and treat it
// as if it were a standard (plain) socket.
socket = sf.createSocket(HOST, PORT);
doQuery(socket);
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (socket != null ) {
try {
socket.close();
}
catch (IOException e) {
// oh, well
}
}
System.exit( 0 );
}
}
private void doQuery(Socket s) throws Exception {
BufferedWriter bw = new BufferedWriter( new OutputStreamWriter(s.getOutputStream()));
BufferedReader br = new BufferedReader( new InputStreamReader(s.getInputStream()));
bw.write(QUESTION + " \n " );
bw.flush();
String response = br.readLine();
if ( ! ANSWER.equals(response)) {
throw new RuntimeException( " Wrong answer: \ "" + response + " \ "" );
}
System.out.println( " Got the right answer: \ "" + response + " \ "" );
}
}