Keytool工具生成SSL證書以及在Java中實(shí)現(xiàn)SSL

1.Keytool工具生成SSL證書

? ? keytool即JDK中自帶的證書生成工具慨代,常見的還有openssl工具。

? ? ?1.生成一個自簽名的CA證書,為了給Client和Server的證書簽名活玲。

? ? ? 命令:keytool -genkeypair (-keyalg RSA) -alias TEST_ROOT -keystore test_root.jks

? ? ? 解釋:生成一對密鑰潮饱,存儲在test_root.jks中,條目別名為TEST_ROOT括尸。輸入該命令后會提示輸入個人信息巷蚪。當(dāng)命令完成后,會在test_root.jks中生成一個自簽名的證書濒翻。當(dāng)然屁柏,私鑰也保存在該文件中。這里密鑰庫的密碼和密鑰密碼都設(shè)置成123456

如果不加keyalg 的有送,默認(rèn)是DSA算法生成

2.為server生成一對密鑰(也就是一個自簽名的證書)

?命令:keytool -genkeypair -alias TEST_SERVER -keystore test_server.jks

解釋:生成一對密鑰淌喻,存儲在test_server.jks中,條目別名TEST_SERVER雀摘。

3.生成一個簽名請求文件(即請求CA給server自簽名的證書簽名)

命令:keytool -certreq -file test_server.csr -alias TEST_SERVER -keystore test_server.jks

解釋:為存儲在test_server.jks中的別名TEST_SERVER生成一個證書請求文件test_server.csr裸删。

4.ca為server的證書簽名

命令:keytool -gencert -infile test_server.csr -outfile test_server.cer -alias TEST_ROOT -keystore TEST_ROOT.jks

解釋:利用TEST_ROOT.jks中條目別名為TEST_ROOT的私鑰為test_server.csr證書請求對應(yīng)的證書簽名,并將簽名后的證書保存在test_server.cer中阵赠。

5.導(dǎo)出ca證書

命令:keytool -exportcert -alias TEST_ROOT -file test_root.cer -keystore test_root.jks

解釋:將test_root.jks中條目別名為TEST_ROOT的證書導(dǎo)出到test_root.cer中涯塔。

6.將ca證書導(dǎo)入到test_server.jks中肌稻。

命令:keytool -importcert -alias TEST_ROOT -file test_root.cer -keystore TEST_SERVER.jks

解釋:將test_root.cer證書文件導(dǎo)入TEST_SERVER.jks中,條目別名為TEST_ROOT伤塌。這里需要注意灯萍,在TEST_SERVER.jks中之前應(yīng)不存在條目別名為TEST_ROOT,這樣才會以信任證書的方式導(dǎo)入每聪。

7.更新server證書

命令:keytool -importcert -alias TEST_SERVER -file test_server.cer -keystore TEST_SERVER.jks

解釋:將test_server.cer導(dǎo)入到TEST_SERVER.jks中旦棉。因?yàn)樵谏蓅erver密鑰對的時候,在test_server.jks中已經(jīng)存在自簽的證書药薯,條目別名為TEST_SERVER绑洛。而該命令保存的別名還是TEST_SERVER。意思上就是更新證書童本。將之前自簽名的證書替換為ca簽名過的證書真屯。

8.查看test_server.jks中server的證書和ca證書。

命令:keytool -list -v -keystore test_server.jks

從條目test_server中可以看出穷娱,該證書被ca簽名后绑蔫,ca的證書也保存在該條目中,形成證書鏈泵额。

對于Client的證書生成參考2-7步配深。在該過程中生成的文件如下:

2.在Java中實(shí)現(xiàn)SSL通信

? Java中主要通過JSSE(Java Secure Socket Extension)來完成安全套接字的編寫。其中主要涉及了一些類嫁盲,例如Keystore篓叶、KeyManagerFactory、TrustManagerFactory羞秤、SSLContext等缸托。它們的關(guān)系如下圖(圖的來源于文章結(jié)尾的鏈接中)

編程的步驟如下:

1.利用keystore類完成客戶端和服務(wù)器的證書庫和信任庫的加載

2.利用加載的證書庫和信任庫,完成KeyManagerFactory和TrustManagerFactory的初始化瘾蛋。

3.生成SSLContext對象俐镐,并用keyManagerFactory和TrustManagerFactory生成的keyManager和TrustManager完成初始化。

4.利用SSLContext對象哺哼,生成對應(yīng)的SSLSocket和SSLServerSocket京革。

需要的文件

1.test_root.jks(存儲了ca證書,因?yàn)閏lient和server的證書都是被ca簽名的幸斥,所以ca證書被信任匹摇,則client和server的證書都會被信任)。

2.test_client.jks(存儲了client的證書)甲葬。

3.test_server.jks(存儲了server的證書)廊勃。

客戶端代碼

public class Client {

? ? public static void main(String[] args) throws Exception {

? ? ? ? String clientKeyStoreFile = "d:\\keystore\\test_client.jks";

? ? ? ? String clientKeyStorePwd = "123456";

? ? ? ? String clientKeyPwd = "123456";

? ? ? ? String clientTrustKeyStoreFile = "d:\\keystore\\test_root.jks";

? ? ? ? String clientTrustKeyStorePwd = "123456";

? ? ? ? //生成client的keystore對象

? ? ? ? KeyStore clientKeyStore = KeyStore.getInstance("JKS");

? ? ? ? clientKeyStore.load(new FileInputStream(clientKeyStoreFile), clientKeyStorePwd.toCharArray());

? ? ? ? //生成信任證書的keystore對象

? ? ? ? KeyStore clientTrustKeyStore = KeyStore.getInstance("JKS");

? ? ? ? clientTrustKeyStore.load(new FileInputStream(clientTrustKeyStoreFile), clientTrustKeyStorePwd.toCharArray());

? ? ? ? KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());

? ? ? ? kmf.init(clientKeyStore, clientKeyPwd.toCharArray());

? ? ? ? TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

? ? ? ? tmf.init(clientTrustKeyStore);

? ? ? ? SSLContext sslContext = SSLContext.getInstance("TLSv1");

? ? ? ? sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);


? ? ? ? SSLSocketFactory socketFactory = sslContext.getSocketFactory();

? ? ? ? Socket socket = socketFactory.createSocket("localhost", Server.SERVER_PORT);


? ? ? ? PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

? ? ? ? BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

? ? ? ? send("hello", out);

? ? ? ? send("exit", out);

? ? ? ? receive(in);

? ? ? ? socket.close();

? ? }


? ? public static void send(String s, PrintWriter out) throws IOException {

? ? ? ? System.out.println("Sending: " + s);? ?

? ? ? ? out.println(s);

? ? }

? ? public static void receive(BufferedReader in) throws IOException {

? ? ? ? String s;

? ? ? ? while ((s = in.readLine()) != null) {

? ? ? ? ? ? System.out.println("Reveived: " + s);

? ? ? ? }

? ? }

}

服務(wù)器代碼

public class Server implements Runnable,HandshakeCompletedListener {

????public static final int SERVER_PORT = 11123;

? ? private final Socket s;

? ? private String peerCerName;

? ? public Server(Socket s) {

? ? ? this.s = s;

? ? }

? ? public static void main(String[] args) throws Exception {

? ? ? ? String serverKeyStoreFile = "d:\\keystore\\test_server.jks";

? ? ? ? String serverKeyStorePwd = "123456";

? ? ? ? String ServerKeyPwd = "123456";

? ? ? ? String serverTrustKeyStoreFile = "d:\\keystore\\test_root.jks";

? ? ? ? String serverTrustKeyStorePwd = "123456";

? ? ? ? /*

? ? ? ? * 加載server.keystore

? ? ? ? *

? ? ? ? */

? ? ? ? KeyStore serverKeyStore = KeyStore.getInstance("JKS");

? ? ? ? serverKeyStore.load(new FileInputStream(serverKeyStoreFile), serverKeyStorePwd.toCharArray());

? ? ? ? /*

? ? ? ? * 加載servertrust.keystore

? ? ? ? *

? ? ? ? */

? ? ? ? KeyStore serverTrustKeyStore = KeyStore.getInstance("JKS");

? ? ? ? serverTrustKeyStore.load(new FileInputStream(serverTrustKeyStoreFile), serverTrustKeyStorePwd.toCharArray());

? ? ? ? KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());

? ? ? ? kmf.init(serverKeyStore, ServerKeyPwd.toCharArray());

? ? ? ? TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

? ? ? ? tmf.init(serverTrustKeyStore);

? ? ? ? SSLContext sslContext = SSLContext.getInstance("TLSv1");

? ? ? ? sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

? ? ? ? SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory();

? ? ? ? SSLServerSocket sslServerSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(SERVER_PORT);

? ? ? ? //設(shè)置雙向驗(yàn)證

? ? ? ? sslServerSocket.setNeedClientAuth(true);

? ? ? ? while (true) {

? ? ? ? ? ? SSLSocket s = (SSLSocket)sslServerSocket.accept();

? ? ? ? ? ? Server cs = new Server(s);

? ? ? ? ? ? s.addHandshakeCompletedListener(cs);

? ? ? ? ? ? new Thread(cs).start();

? ? ? ? }

? ? }

? ? @Override

? ? public void run() {

? ? ? ? try {

? ? ? ? ? ? BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream()));

? ? ? ? ? ? PrintWriter writer = new PrintWriter(s.getOutputStream(), true);

? ? ? ? ? ? writer.println("Welcome~, enter exit to leave.");

? ? ? ? ? ? String message;

? ? ? ? ? ? while ((message = reader.readLine()) != null && !message.trim().equalsIgnoreCase("exit")) {

? ? ? ? ? ? ? ? writer.println("Echo: " + message);

? ? ? ? ? ? }

? ? ? ? ? ? writer.println("Bye~, " + peerCerName);

? ? ? ? } catch (Exception e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? } finally {

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? s.close();

? ? ? ? ? ? } catch (IOException e) {

? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? }

? ? ? ? }

? ? }

? ? @Override

? ? public void handshakeCompleted(HandshakeCompletedEvent event) {

? ? ? ? try {

? ? ? ? ? ? X509Certificate cert = (X509Certificate) event.getPeerCertificates()[0];

? ? ? ? ? ? peerCerName = cert.getSubjectX500Principal().getName();

? ? ? ? } catch (SSLPeerUnverifiedException ex) {

? ? ? ? ? ? ex.printStackTrace();

? ? ? ? }

? ? }

}

運(yùn)行結(jié)果:

說明SSL握手成功建立。

參考的文章:https://www.ibm.com/developerworks/cn/java/j-lo-socketkeytool/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市坡垫,隨后出現(xiàn)的幾起案子梭灿,更是在濱河造成了極大的恐慌,老刑警劉巖冰悠,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件堡妒,死亡現(xiàn)場離奇詭異,居然都是意外死亡溉卓,警方通過查閱死者的電腦和手機(jī)皮迟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來桑寨,“玉大人伏尼,你說我怎么就攤上這事∥疚玻” “怎么了爆阶?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長沙咏。 經(jīng)常有香客問我辨图,道長,這世上最難降的妖魔是什么肢藐? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任徒役,我火速辦了婚禮,結(jié)果婚禮上窖壕,老公的妹妹穿的比我還像新娘。我一直安慰自己杉女,他們只是感情好瞻讽,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著熏挎,像睡著了一般速勇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上坎拐,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天烦磁,我揣著相機(jī)與錄音,去河邊找鬼哼勇。 笑死都伪,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的积担。 我是一名探鬼主播陨晶,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼帝璧!你這毒婦竟也來了先誉?” 一聲冷哼從身側(cè)響起湿刽,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎褐耳,沒想到半個月后诈闺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡铃芦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年雅镊,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片杨帽。...
    茶點(diǎn)故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡漓穿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出注盈,到底是詐尸還是另有隱情晃危,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布老客,位于F島的核電站僚饭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏胧砰。R本人自食惡果不足惜鳍鸵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望尉间。 院中可真熱鬧偿乖,春花似錦、人聲如沸哲嘲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽眠副。三九已至画切,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間囱怕,已是汗流浹背霍弹。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留娃弓,地道東北人典格。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像台丛,于是被迫代替她去往敵國和親钝计。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容