概念
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?+?
"
\
""
);
??}
}
以上方法主要参考了如下两个网页:
http://www.churchillobjects.com/c/11201g.html
http://mark.foster.cc/kb/openssl-keytool.html
posted on 2006-12-03 12:36
我爱佳娃 阅读(176)
评论(0) 编辑 收藏 引用 收藏至365Key 所属分类:
SSL