用OpenSSL与JAVA(JSSE)通信

论坛 期权论坛 脚本     
匿名技术用户   2020-12-22 06:10   37   0

概念
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.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 + " / "" );
}

}


分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP