Windows 10 x64 專業版 編譯與測試【調試】Openssl【OpenSSL_1_0_2h】之 TLS

本人出於對 OpenSSL 的 TLS 協議的好奇,而走上了調試 OpenSSL 的道路。

在調試過程中也遇到過很多的坑,現在調試成功了,便記錄下來,方便日後查看,

由於各種原因,我選擇的 OpenSSL 的版本爲: OpenSSL_1_0_2h

目錄

0x01 下載 OpenSSL 源碼

0x02 配置開發環境

0x03 編譯 OpenSSL

0x04 編譯帶符號的 OpenSSL【Debug 版本】

0x05 輸出結果對比

0x06 調試 OpenSSL 的源代碼

0x07 調試 OpenSSL 的相關配置

0x08 使用 Wireshark 抓包分析 TLS 協議

 

0x01 下載 OpenSSL 源碼

OpenSSL下載地址如下【也可以自己去 OpenSSL 的官網找】:

OpenSSL_1_0_2h:https://www.openssl.org/source/old/1.0.2/openssl-1.0.2h.tar.gz

OpenSSL官網: https://www.openssl.org/

下載好 OpenSSL 之後解壓出來,我的解壓路徑是:

E:\OpenSSL\openssl-OpenSSL_1_0_2h\

解壓出來就可以看到 OpenSSL 的目錄結構了,如下圖所示:

 

0x02 配置開發環境

下載好 OpenSSL 源碼之後就可以開始進行編譯了,由於我們是在 Windows 上編譯,因此,與編譯相關的信息可以查看源碼根目錄下的 【INSTALL】和【INSTALL.W32】文件,裏面有關於編譯命令的解釋說明。但是,在編譯之前,我們需要安裝 Perl,於是去 Perl.org 【https://www.perl.org/get.html#win32】官網下載好Perl,並安裝好。當然,VC6編譯器也是需要有一個的,我使用的是VS2010,打開 VS2010 的命令提示符,如下圖所示:

我們不使用 X64 版本的,因爲我們要編譯 32 位的 DLL。

注:


這裏關於Win 10 上的 Perl 有個坑,我安裝的Perl 是 5.16.2 版本,在命令行中輸入:

> Perl test.pl 

的時候,不是執行 test.pl 這個腳本文件,而是直接進入Perl 交互模式,這就非常蛋疼了,因爲在配置 OpenSSL 的時候用到這樣的命令,如果這樣沒辦法執行腳本,那就沒辦法配置 OpenSSL 了,於是我就直接在 Perl 安裝的目錄下【默認是 C:\Perl\】,把原來的 bin 文件夾中的 Perl.exe 刪除掉,然後把 perl5.16.2.exe 複製一份,重命名爲 Perl.exe 【也是在bin文件夾中】,如下圖所示:

這才變成我們常用的模式,這樣的話,在命令行中輸入

> Perl test.pl 

就會是直接執行 test.pl 這個腳本了,而不是進入交互模式,如下圖所示:

【如果你沒有遇到這個問題,則可以忽略這個部分】


 

0x03 編譯 OpenSSL

以上步驟都完成之後,我們就可以進行編譯工作了,因爲不同的 OpenSSL 版本的編譯命令可能會不太一樣,所以,如果你是用別的版本的 OpenSSL 的話,有可能要用別的命令來編譯,現在我們使用的是: OpenSSL_1_0_2h 

默認編譯的是 Release 版本,使用的命令如下:

【在VS2010 命令行中執行】

> Perl Configure VC-WIN32 no-asm --prefix=C:\MyProgramFiles\OpenSSLv1.0.2h --openssldir=C:\MyProgramFiles\OpenSSLv1.0.2h\SSL
> ms\do_ms
> nmake -f ms\ntdll.mak
> rem 如果你要安裝,則執行以下這條命令
> nmake -f ms\ntdll.mak install   
> rem 清空編譯的中間結果
> rem nmake -f ms\ntdll.mak clean

rem 是CMD中的註釋命令】

這裏的 --prefix 和 --openssldir 選項可以不需要,因爲這兩個選項是用來指定 OpenSSL 的安裝路徑的,我們只要編譯,可以不用安裝就可以使用了的。編譯完成之後,在 OpenSSL 的根目錄下就會生成一個【/out32dll】 的目錄,裏面包含了我們需要的文件 libeay32.dll 、libeay32.lib 、ssleay32.dll 、ssleay32.lib openssl.exe, 當然還有頭文件所在的目錄 【/inc32】。如下圖所示:

然後我們就可以新建一個項目【例如用VS2010等】,測試 OpenSSL 了,但是這裏編譯出來的 OpenSSL 是 Release 版本的,很多符號信息都會被丟棄掉,在調試的過程中,如果想要進入OpenSSL內部調試它的代碼,很多變量的信息就丟失了,如下圖所示:

因此,調試起來就非常的不舒服,很多時候我們都需要看這些函數內部的變量信息,而現在卻得不到,表示很不爽。

 

0x04 編譯帶符號的 OpenSSL【Debug 版本】

現在我們編譯帶符號的OpenSSL版本,並且添加很多的宏,這些宏使得 OpenSSL 在運行的過程中輸出大量的對我們有用的信息,例如 TLS 協議中的重要參數信息: PreMasterKey, MasterKey, KEY_BLOCK 等等。

我們在配置 OpenSSL 的時候給它添加如下的宏:

  • DEBUG
  • _DEBUG
  • OPENSSL_DEBUG_KEYGEN
  • SSL_DEBUG
  • ALG_DEBUG
  • CIPHER_DEBUG
  • TLS_DEBUG
  • KSSL_DEBUG

具體的編譯命令如下:

rem 編譯 debug 版本,並且輸出 大量LOG日誌信息,包括 MasterKey 等。
> Perl Configure -DDEBUG -D_DEBUG -DOPENSSL_DEBUG_KEYGEN -DSSL_DEBUG -DALG_DEBUG -DCIPHER_DEBUG  -DTLS_DEBUG  -DKSSL_DEBUG debug-VC-WIN32 no-asm --prefix=C:\MyProgramFiles\OpenSSLv1.0.2h --openssldir=C:\MyProgramFiles\OpenSSLv1.0.2h\SSL
> ms\do_ms
> nmake -f ms\ntdll.mak

執行完以上命令之後,就生成了一個 Debug 版本的 OpenSSL,對應的 dll 文件和 lib 文件在 目錄【/out32dll.dbg】中,而頭文件還是在目錄 【/inc32】中,這時候調試就會有符號信息了,

但是還有一個大坑,那就是運行時會出現如下錯誤:

OPENSSL_Uplink(0098E000,07): no OPENSSL_Applink 錯誤

找了很久之後,通過翻閱 OpenSSL 的源代碼,自己想到了一個很好的解決方法,那就是把 :

E:\OpenSSL\openssl-OpenSSL_1_0_2h\crypto\bio\b_dump.c 文件中的一個宏直接改掉,

如下圖所示:

因爲這裏的 UP_fwrite 是一個宏定義,而正是由於這個宏定義導致了 APPLINK的錯誤,所以我們把這個宏直接改掉,把UP_fwrite直接改成 fwrite 即可,然後再編譯,程序就一切正常了,如下圖所示:

 

0x05 輸出結果對比

使用 Release 版本的 OpenSSL 的輸出結果:

使用 Debug 版本的 OpenSSL 輸出了非常多的調試信息,如下圖所示:

具體信息如下:

// Client 端的輸出

ssl_create_cipher_list() for 125 ciphers
        0: ECDH-RSA-AES256-GCM-SHA384 300c032 20 10
        1: ECDH-RSA-AES128-GCM-SHA256 300c031 20 10
        2: ECDHE-RSA-AES256-GCM-SHA384 300c030 80 1
        ......
        122: RC4-MD5 3000004 1 1
        123: NULL-SHA 3000002 1 1
        124: NULL-MD5 3000001 1 1
Applying rule 1 with 00000080/00000000/00000000/00000000/00000000 00000000 (-1)

Name: ECDH-RSA-AES256-GCM-SHA384:
Algo = 00000020/00000010/00002000/00000040/00000004 Algo_strength = 00000181

Name: ECDH-RSA-AES128-GCM-SHA256:
Algo = 00000020/00000010/00001000/00000040/00000004 Algo_strength = 00000181

...........

Name: ECDH-ECDSA-DES-CBC3-SHA:
Algo = 00000040/00000010/00000002/00000002/00000002 Algo_strength = 00000181

Name: DES-CBC3-SHA:
Algo = 00000001/00000001/00000002/00000002/00000002 Algo_strength = 00000181

Name: PSK-3DES-EDE-CBC-SHA:
Algo = 00000100/00000080/00000002/00000002/00000002 Algo_strength = 00000181
<ECDHE-RSA-AES256-GCM-SHA384>
<ECDHE-ECDSA-AES256-GCM-SHA384>

...........

<ECDH-RSA-DES-CBC3-SHA>
<ECDH-ECDSA-DES-CBC3-SHA>
<DES-CBC3-SHA>
<PSK-3DES-EDE-CBC-SHA>
socket created
address created
server connected
tls1_enc(1)
tls1_enc(0)
dec 58
02 00 00 36 03 03 EA 77 65 22 30 A6 92 36 8C 3C
8C 77 77 8F 05 DE 26 B4 4F 9D BE 07 AB 9E 57 AB
F4 68 4B FF 84 39 00 00 9D 00 00 0E FF 01 00 01
00 00 23 00 00 00 0F 00 01 01
tls1_enc(0)
dec 867
0B 00 03 5F 00 03 5C 00 03 59 30 82 03 55 30 82
02 3D A0 03 02 01 02 02 01 01 30 0D 06 09 2A 86
48 86 F7 0D 01 01 0B 05 00 30 7B 31 0B 30 09 06
03 55 04 06 13 02 43 4E 31 11 30 0F 06 03 55 04
08 0C 08 53 68 61 6E 67 48 61 69 31 11 30 0F 06
03 55 04 07 0C 08 53 68 61 6E 67 48 61 69 31 0D
30 0B 06 03 55 04 0A 0C 04 53 4A 54 55 31 0D 30
0B 06 03 55 04 0B 0C 04 53 4A 54 55 31 0B 30 09
06 03 55 04 03 0C 02 6D 6C 31 1B 30 19 06 09 2A
86 48 86 F7 0D 01 09 01 16 0C 73 6A 74 75 40 73
6A 74 75 2E 63 6E 30 1E 17 0D 31 38 30 37 32 38
31 34 32 30 35 31 5A 17 0D 31 39 30 37 32 38 31
34 32 30 35 31 5A 30 68 31 0B 30 09 06 03 55 04
06 13 02 43 4E 31 11 30 0F 06 03 55 04 08 0C 08
53 68 61 6E 67 48 61 69 31 0D 30 0B 06 03 55 04
0A 0C 04 53 4A 54 55 31 0D 30 0B 06 03 55 04 0B
0C 04 53 4A 54 55 31 0B 30 09 06 03 55 04 03 0C
02 6D 6C 31 1B 30 19 06 09 2A 86 48 86 F7 0D 01
09 01 16 0C 73 6A 74 75 40 73 6A 74 75 2E 63 6E
30 81 9F 30 0D 06 09 2A 86 48 86 F7 0D 01 01 01
05 00 03 81 8D 00 30 81 89 02 81 81 00 F7 22 23
3C 4E DF EE BF AC A0 00 8A EA DE 5C BF B6 CF B9
2E D9 F5 04 39 48 34 79 01 04 BE E3 28 A0 C6 A4
D4 9A 92 BA 98 CF 77 05 44 C5 CB 56 F3 A1 FD DE
29 46 1D 88 D2 3E 6D 91 34 37 F4 67 9A 09 E1 C8
C0 1E 2D B0 DD 8A 34 A4 40 FA FD 1D 1D 0E 1D 8B
AF 2F 1D 19 7C C1 25 3E 04 3F B3 4D C6 79 66 39
40 E9 4E D2 85 19 0B 98 1F 6B F7 00 70 68 E9 18
F5 4B 42 E3 C9 C4 AF 75 49 D2 DA 3E A9 02 03 01
00 01 A3 7B 30 79 30 09 06 03 55 1D 13 04 02 30
00 30 2C 06 09 60 86 48 01 86 F8 42 01 0D 04 1F
16 1D 4F 70 65 6E 53 53 4C 20 47 65 6E 65 72 61
74 65 64 20 43 65 72 74 69 66 69 63 61 74 65 30
1D 06 03 55 1D 0E 04 16 04 14 A0 AC 52 D2 F2 A8
54 BF 3C F9 B2 71 57 44 8E 28 4F 85 FC EA 30 1F
06 03 55 1D 23 04 18 30 16 80 14 FD 98 DA AF 30
AC 6E F0 BA 99 36 36 40 98 35 55 C3 99 9D A7 30
0D 06 09 2A 86 48 86 F7 0D 01 01 0B 05 00 03 82
01 01 00 01 64 DD 87 2B 52 FD FF 07 F5 BA 8E 35
7D A7 3E 3F BC 4C F7 7F C9 92 03 60 47 9E 01 27
11 97 89 DF BD 50 D5 A1 A4 5A 06 00 84 9D 6D CA
F2 43 F9 A6 01 B3 49 64 6D B2 27 51 E4 AF 72 88
1F 0D D4 35 BA 28 76 9D 22 97 84 22 16 90 22 E6
02 15 AB CF 55 23 73 83 40 03 05 AD FB 88 AD 95
DC C8 D7 91 4C 32 B7 E5 8D 5D 82 C8 06 16 89 BB
57 23 A4 11 0A C1 8F AC 20 78 3E AC 72 11 1C D7
EB 7E E3 24 97 BA 8B CA D2 67 69 2D 8E 3C 88 42
1B A1 0F 0A 7F CD 49 57 A0 76 48 69 4D DE 94 58
3D 67 BF E2 05 FD D5 A7 72 60 3A FD 38 26 ED D7
4C 19 9E 4F B3 7D 7B 74 B5 6C AB 1A 27 8C 2A E7
E6 89 92 A7 C1 0A 89 A5 5A 11 73 B6 71 A5 E6 7F
E1 89 50 8A A9 F4 3E 95 1C 05 A5 72 A7 35 F6 4F
C3 5A 74 E5 4E ED B6 EF 0F CF 30 09 28 3D 11 9B
BF FA A3 3D 98 FE C2 0B 87 61 E7 E4 33 23 D5 F1
F8 38 FE
pkey,x = 032D2E28, 032CDF68
ssl_cert_type(x,pkey) = 0
cipher, alg, nc = AES256-GCM-SHA384, 1, 1, 1
tls1_enc(0)
dec 4
0E 00 00 00
tls1_generate_master_secret(032BD1E8,032CDE5C, 014FEFA8, 48)
Premaster Secret:
0000 - 03 03 d4 1f 37 33 73 d7-19 33 3e 41 bf 23 0c 9a   ....73s..3>A.#..
0010 - 62 38 ed 14 27 56 9e a7-fa ee a1 d4 37 95 bf bd   b8..'V......7...
0020 - e7 cd fd ba e7 f0 1e b1-40 a7 95 4a f6 c9 ab 54   [email protected]
Client Random:
0000 - a3 cd 3e bb 59 38 31 46-5f 07 97 92 3b 07 d5 37   ..>.Y81F_...;..7
0010 - 36 cd d8 dc 45 ed 01 67-b8 46 97 26 99 8c c1 55   6...E..g.F.&...U
Server Random:
0000 - ea 77 65 22 30 a6 92 36-8c 3c 8c 77 77 8f 05 de   .we"0..6.<.ww...
0010 - 26 b4 4f 9d be 07 ab 9e-57 ab f4 68 4b ff 84 39   &.O.....W..hK..9
Master Secret:
0000 - 76 f0 5b f0 1f 80 9e 49-c0 1d 6a 1f 63 20 86 d4   v.[....I..j.c ..
0010 - 2b 21 75 ba 5b 01 0e d1-60 c6 f9 b7 af 0c 71 fd   +!u.[...`.....q.
0020 - b3 f0 1d e0 01 d2 4e e2-e8 5f 62 88 98 e7 65 aa   ......N.._b...e.
tls1_generate_master_secret() complete
tls1_enc(1)
tls1_enc(1)
tls1_setup_key_block()
client random
A3 CD 3E BB 59 38 31 46 5F 07 97 92 3B 07 D5 37
36 CD D8 DC 45 ED 01 67 B8 46 97 26 99 8C C1 55
server random
EA 77 65 22 30 A6 92 36 8C 3C 8C 77 77 8F 05 DE
26 B4 4F 9D BE 07 AB 9E 57 AB F4 68 4B FF 84 39
pre-master
76 F0 5B F0 1F 80 9E 49 C0 1D 6A 1F 63 20 86 D4
2B 21 75 BA 5B 01 0E D1 60 C6 F9 B7 AF 0C 71 FD
B3 F0 1D E0 01 D2 4E E2 E8 5F 62 88 98 E7 65 AA
tls1_generate_key_block() ==> 48 byte master_key =
        76F05BF01F809E49C01D6A1F632086D42B2175BA5B010ED160C6F9B7AF0C71FDB3F01DE001D24EE2E85F628898E765AA

key block
D0 9E 36 21 BE 74 3E DF C3 0D B5 BA 01 E4 B1 DC
A4 79 1E 7D 2A 8D 4F 7E 0B F9 EB 67 39 B2 7F 18
C0 FD AC 39 28 10 EC 11 55 5E B0 AD A6 9E 9D 38
DB 3E 24 80 9D CE FD 77 9D 6E 71 64 44 71 E0 7F
C7 9F 28 48 59 9F A1 E1 BA 2D 78 99 B1 34 6E B6
2E 77 8B 4F 0B 88 CA A8 tls1_change_cipher_state(which= 18) w/
        alg= 1/1, comp= 00000000
        evp_cipher == 1008F0B0 ==? &d_cbc_ede_cipher3
        evp_cipher: nid, blksz= 901, 1, keylen=32, ivlen=12
        key_block: len= 88, data= d09e3621be743edfc30db5ba01e4b1dca4791e7d2a8d4f7e0bf9eb6739b27f18c0fdac392810ec11555eb0ada69e9d38db3e24809dcefd779d6e71644471e07fc79f2848599fa1e1ba2d7899b1346eb62e778b4f0b88caa8
which = 0012
mac key=EVP_CipherInit_ex(dd,c,key=,iv=,which)
        key= d09e3621be743edfc30db5ba01e4b1dca4791e7d2a8d4f7e0bf9eb6739b27f18
         iv= c79f2848599fa1e1ba2d7899
which = 0012
key=D0 9E 36 21 BE 74 3E DF C3 0D B5 BA 01 E4 B1 DC
A4 79 1E 7D 2A 8D 4F 7E 0B F9 EB 67 39 B2 7F 18

iv=C7 9F 28 48
tls1_enc(1)
EVP_Cipher(ds=032CF690,rec->data=032C77E0,rec->input=032C77E0,l=40) ==>
        EVP_CIPHER_CTX: 0 buf_len, 32 key_len [8 128], 12 iv_len
                IV: C79F2848442E2C6C0AA60B07
        rec->input= 01 00 00 82 00 80 ea 0e 14 00 00 0c df 67 a9 c1 b0 47 c5 5f b8 45 d5 f3 5d f5 79 92 9f ef 9a f8 8c 14 d3 e9 d5 87 f4 b1
        rec->data= 44 2e 2c 6c 0a a6 0b 07 da 74 5e 6f 16 56 f5 bc 5b e4 b1 a2 c1 31 66 e8 13 a9 2f d2 79 e8 1a d3 cf 9f a5 88 3f 1d dd df
tls1_enc(0)
dec 170
04 00 00 A6 00 00 1C 20 00 A0 E3 F1 7E 5C 48 EA
D0 D5 25 B8 77 E0 F7 8A F6 0A 49 18 21 3D ED 52
84 D5 B1 8F 0F A5 10 EE 09 AE 17 E0 A0 C7 70 CC
F0 DD 3B 46 A7 B8 00 3B 3A 80 37 24 05 85 C0 7D
73 12 BF AF 95 46 12 57 4A EF 26 10 96 C3 0A 44
80 88 D4 64 FF 2F ED 05 EA E6 BA 37 79 D4 A3 7E
34 8E 54 3F 85 52 27 0E 04 52 75 39 E3 D3 70 26
13 13 CB 7D 52 35 94 ED F2 3D 73 80 7F F1 2C A6
3D 4E 62 8C B0 44 4A 9C 2E AC DE 95 75 E2 79 34
AE 02 8C 18 51 3A 5C 81 66 9D B1 84 A3 E0 CD B1
9C 4E 6A B6 36 10 0D 31 FF 35
tls1_enc(0)
dec 1
01
tls1_change_cipher_state(which= 17) w/
        alg= 1/1, comp= 00000000
        evp_cipher == 1008F0B0 ==? &d_cbc_ede_cipher3
        evp_cipher: nid, blksz= 901, 1, keylen=32, ivlen=12
        key_block: len= 88, data= d09e3621be743edfc30db5ba01e4b1dca4791e7d2a8d4f7e0bf9eb6739b27f18c0fdac392810ec11555eb0ada69e9d38db3e24809dcefd779d6e71644471e07fc79f2848599fa1e1ba2d7899b1346eb62e778b4f0b88caa8
which = 0011
mac key=EVP_CipherInit_ex(dd,c,key=,iv=,which)
        key= c0fdac392810ec11555eb0ada69e9d38db3e24809dcefd779d6e71644471e07f
         iv= 599fa1e1ba2d7899b1346eb6
which = 0011
key=C0 FD AC 39 28 10 EC 11 55 5E B0 AD A6 9E 9D 38
DB 3E 24 80 9D CE FD 77 9D 6E 71 64 44 71 E0 7F

iv=59 9F A1 E1
tls1_enc(0)
EVP_Cipher(ds=032CF418,rec->data=032C3268,rec->input=032C3268,l=40) ==>
        EVP_CIPHER_CTX: 0 buf_len, 32 key_len [8 128], 12 iv_len
                IV: 599FA1E10000000000000000
        rec->input= 85 97 a5 75 ca b5 75 90 08 ad 86 3c e0 73 61 37 f1 ba 51 40 69 fe 6e fb f8 ee 13 c0 5b 70 68 ee eb 0c f1 8d d4 7a e2 64
        rec->data= 14 00 00 0c ce 42 da 39 00 b7 ed f3 c3 8e 60 b7 f8 ee 13 c0 5b 70 68 ee eb 0c f1 8d d4 7a e2 64 09 ae 17 e0 a0 c7 70 cc
dec 16
14 00 00 0C CE 42 DA 39 00 B7 ED F3 C3 8E 60 B7

Connected with AES256-GCM-SHA384 encryption
數字證書信息:
證書: /C=CN/ST=ShangHai/O=SJTU/OU=SJTU/CN=ml/[email protected]
頒發者: /C=CN/ST=ShangHai/L=ShangHai/O=SJTU/OU=SJTU/CN=ml/[email protected]
tls1_enc(0)
EVP_Cipher(ds=032CF418,rec->data=032C3268,rec->input=032C3268,l=38) ==>
        EVP_CIPHER_CTX: 0 buf_len, 32 key_len [8 128], 12 iv_len
                IV: 599FA1E18597A575CAB57590
        rec->input= 85 97 a5 75 ca b5 75 91 17 97 78 c4 a4 dc 28 0e 00 09 dd 21 ef 5f 28 c7 19 0a c2 c3 70 bc 9b 11 29 6e ec a0 bf bd
        rec->data= 73 65 72 76 65 72 2d 3e 63 6c 69 65 6e 74 28 c7 19 0a c2 c3 70 bc 9b 11 29 6e ec a0 bf bd e2 64 09 ae 17 e0 a0 c7
dec 14
73 65 72 76 65 72 2D 3E 63 6C 69 65 6E 74
接收消息成功:'server->client',共14個字節的數據
tls1_enc(1)
EVP_Cipher(ds=032CF690,rec->data=032C77E0,rec->input=032C77E0,l=43) ==>
        EVP_CIPHER_CTX: 0 buf_len, 32 key_len [8 128], 12 iv_len
                IV: C79F2848442E2C6C0AA60B08
        rec->input= 44 2e 2c 6c 0a a6 0b 07 66 72 6f 6d 20 63 6c 69 65 6e 74 2d 3e 73 65 72 76 65 72 d2 79 e8 1a d3 cf 9f a5 88 3f 1d dd df 06 0c 8e
        rec->data= 44 2e 2c 6c 0a a6 0b 08 2c c2 3e d4 3b d7 ac f7 26 d7 45 36 10 1d a1 d6 10 cc fd cd 24 8a 50 c7 ff 61 e3 cf a7 11 24 b4 f3 c3 18
消息'from client->server'發送成功,共發送了19個字節!
tls1_enc(1)
EVP_Cipher(ds=032CF690,rec->data=032C77E0,rec->input=032C77E0,l=26) ==>
        EVP_CIPHER_CTX: 0 buf_len, 32 key_len [8 128], 12 iv_len
                IV: C79F2848442E2C6C0AA60B09
        rec->input= 44 2e 2c 6c 0a a6 0b 08 01 00 3e d4 3b d7 ac f7 26 d7 45 36 10 1d a1 d6 10 cc
        rec->data= 44 2e 2c 6c 0a a6 0b 09 9d 8d 76 5f 99 8f 5e 13 be b2 0a 6c df a5 be 26 47 0c
請按任意鍵繼續. . .
// Server 端的輸出也類似,

ssl_create_cipher_list() for 125 ciphers
        0: ECDH-RSA-AES256-GCM-SHA384 300c032 20 10
        1: ECDH-RSA-AES128-GCM-SHA256 300c031 20 10

       ...........

        121: RC4-SHA 3000005 1 1
        122: RC4-MD5 3000004 1 1
        123: NULL-SHA 3000002 1 1
        124: NULL-MD5 3000001 1 1
Applying rule 1 with 00000080/00000000/00000000/00000000/00000000 00000000 (-1)

Name: ECDH-RSA-AES256-GCM-SHA384:
Algo = 00000020/00000010/00002000/00000040/00000004 Algo_strength = 00000181

Name: ECDH-RSA-AES128-GCM-SHA256:
Algo = 00000020/00000010/00001000/00000040/00000004 Algo_strength = 00000181

..........

Name: DES-CBC3-SHA:
Algo = 00000001/00000001/00000002/00000002/00000002 Algo_strength = 00000181

Name: PSK-3DES-EDE-CBC-SHA:
Algo = 00000100/00000080/00000002/00000002/00000002 Algo_strength = 00000181
<ECDHE-RSA-AES256-GCM-SHA384>
<ECDHE-ECDSA-AES256-GCM-SHA384>

...........

<ECDH-RSA-DES-CBC3-SHA>
<ECDH-ECDSA-DES-CBC3-SHA>
<DES-CBC3-SHA>
<PSK-3DES-EDE-CBC-SHA>
socket created
binded
begin listen
server: got connection from 10.162.143.68, port 15512, socket 384
tls1_enc(0)
dec 302
01 00 01 2A 03 03 A3 CD 3E BB 59 38 31 46 5F 07
97 92 3B 07 D5 37 36 CD D8 DC 45 ED 01 67 B8 46
97 26 99 8C C1 55 00 00 AC C0 30 C0 2C C0 28 C0
24 C0 14 C0 0A 00 A5 00 A3 00 A1 00 9F 00 6B 00
6A 00 69 00 68 00 39 00 38 00 37 00 36 00 88 00
87 00 86 00 85 C0 32 C0 2E C0 2A C0 26 C0 0F C0
05 00 9D 00 3D 00 35 00 84 C0 2F C0 2B C0 27 C0
23 C0 13 C0 09 00 A4 00 A2 00 A0 00 9E 00 67 00
40 00 3F 00 3E 00 33 00 32 00 31 00 30 00 9A 00
99 00 98 00 97 00 45 00 44 00 43 00 42 C0 31 C0
2D C0 29 C0 25 C0 0E C0 04 00 9C 00 3C 00 2F 00
96 00 41 00 07 C0 11 C0 07 C0 0C C0 02 00 05 00
04 C0 12 C0 08 00 16 00 13 00 10 00 0D C0 0D C0
03 00 0A 00 FF 01 00 00 55 00 0B 00 04 03 00 01
02 00 0A 00 1C 00 1A 00 17 00 19 00 1C 00 1B 00
18 00 1A 00 16 00 0E 00 0D 00 0B 00 0C 00 09 00
0A 00 23 00 00 00 0D 00 20 00 1E 06 01 06 02 06
03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03
02 03 03 02 01 02 02 02 03 00 0F 00 01 01
Server has 98 from 02D28530:
0F8B46E0:ECDHE-RSA-AES256-GCM-SHA384
0F8B4620:ECDHE-ECDSA-AES256-GCM-SHA384

...........

0F8B4050:ECDH-RSA-DES-CBC3-SHA
0F8B3E70:ECDH-ECDSA-DES-CBC3-SHA
0F8B30F0:DES-CBC3-SHA
rt=0 rte=0 dht=0 ecdht=0 re=1 ree=1 rs=0 ds=0 dhr=0 dhd=0
0:[00000080:00000001:00000101:00000085]0F8B46E0:ECDHE-RSA-AES256-GCM-SHA384
rt=0 rte=0 dht=0 ecdht=0 re=1 ree=1 rs=0 ds=0 dhr=0 dhd=0
0:[00000080:00000040:00000101:00000085]0F8B4620:ECDHE-ECDSA-AES256-GCM-SHA384
rt=0 rte=0 dht=0 ecdht=0 re=1 ree=1 rs=0 ds=0 dhr=0 dhd=0

...........

rt=0 rte=0 dht=0 ecdht=0 re=1 ree=1 rs=0 ds=0 dhr=0 dhd=0
0:[00000040:00000010:00000101:00000085]0F8B3ED0:ECDH-ECDSA-AES256-SHA
rt=0 rte=0 dht=0 ecdht=0 re=1 ree=1 rs=0 ds=0 dhr=0 dhd=0
1:[00000001:00000001:00000101:00000085]0F8B3C00:AES256-GCM-SHA384
tls1_enc(1)
rt=0 rte=0 dht=0 ecdht=0 re=1 ree=1 rs=0 ds=0 dhr=0 dhd=0
tls1_enc(1)
tls1_enc(1)
tls1_enc(0)
dec 134
10 00 00 82 00 80 EA 0E C9 02 FC DB 63 5B 1F F6
73 A4 88 20 4F BA 45 26 5D F5 79 92 9F EF 9A F8
8C 14 D3 E9 D5 87 F4 B1 06 0C 8E 9E F1 6A D3 AB
0A 80 88 2E 61 26 1D 7B D6 C8 52 64 9E 8C DC 4C
02 25 8B A5 9B 4B 1C 42 18 45 08 F7 26 8C DA 48
7B 7B 5B 9A DD D2 C1 4E 4A 36 01 0A 07 0B 33 B6
F4 24 49 2C 34 D5 5E 56 DE 5D F9 05 C0 8C 68 F4
A2 84 EA 8A 1F 52 53 54 D8 E2 93 90 1F 57 DC FB
C3 09 CA C8 C5 0F
tls1_generate_master_secret(02D62250,02D5D4BC, 02D62ACE, 48)
Premaster Secret:
0000 - 03 03 d4 1f 37 33 73 d7-19 33 3e 41 bf 23 0c 9a   ....73s..3>A.#..
0010 - 62 38 ed 14 27 56 9e a7-fa ee a1 d4 37 95 bf bd   b8..'V......7...
0020 - e7 cd fd ba e7 f0 1e b1-40 a7 95 4a f6 c9 ab 54   [email protected]
Client Random:
0000 - a3 cd 3e bb 59 38 31 46-5f 07 97 92 3b 07 d5 37   ..>.Y81F_...;..7
0010 - 36 cd d8 dc 45 ed 01 67-b8 46 97 26 99 8c c1 55   6...E..g.F.&...U
Server Random:
0000 - ea 77 65 22 30 a6 92 36-8c 3c 8c 77 77 8f 05 de   .we"0..6.<.ww...
0010 - 26 b4 4f 9d be 07 ab 9e-57 ab f4 68 4b ff 84 39   &.O.....W..hK..9
Master Secret:
0000 - 76 f0 5b f0 1f 80 9e 49-c0 1d 6a 1f 63 20 86 d4   v.[....I..j.c ..
0010 - 2b 21 75 ba 5b 01 0e d1-60 c6 f9 b7 af 0c 71 fd   +!u.[...`.....q.
0020 - b3 f0 1d e0 01 d2 4e e2-e8 5f 62 88 98 e7 65 aa   ......N.._b...e.
tls1_generate_master_secret() complete
tls1_enc(0)
dec 1
01
tls1_setup_key_block()
client random
A3 CD 3E BB 59 38 31 46 5F 07 97 92 3B 07 D5 37
36 CD D8 DC 45 ED 01 67 B8 46 97 26 99 8C C1 55
server random
EA 77 65 22 30 A6 92 36 8C 3C 8C 77 77 8F 05 DE
26 B4 4F 9D BE 07 AB 9E 57 AB F4 68 4B FF 84 39
pre-master
76 F0 5B F0 1F 80 9E 49 C0 1D 6A 1F 63 20 86 D4
2B 21 75 BA 5B 01 0E D1 60 C6 F9 B7 AF 0C 71 FD
B3 F0 1D E0 01 D2 4E E2 E8 5F 62 88 98 E7 65 AA
tls1_generate_key_block() ==> 48 byte master_key =
        76F05BF01F809E49C01D6A1F632086D42B2175BA5B010ED160C6F9B7AF0C71FDB3F01DE001D24EE2E85F628898E765AA

key block
D0 9E 36 21 BE 74 3E DF C3 0D B5 BA 01 E4 B1 DC
A4 79 1E 7D 2A 8D 4F 7E 0B F9 EB 67 39 B2 7F 18
C0 FD AC 39 28 10 EC 11 55 5E B0 AD A6 9E 9D 38
DB 3E 24 80 9D CE FD 77 9D 6E 71 64 44 71 E0 7F
C7 9F 28 48 59 9F A1 E1 BA 2D 78 99 B1 34 6E B6
2E 77 8B 4F 0B 88 CA A8 tls1_change_cipher_state(which= 33) w/
        alg= 1/1, comp= 00000000
        evp_cipher == 0FA8F0B0 ==? &d_cbc_ede_cipher3
        evp_cipher: nid, blksz= 901, 1, keylen=32, ivlen=12
        key_block: len= 88, data= d09e3621be743edfc30db5ba01e4b1dca4791e7d2a8d4f7e0bf9eb6739b27f18c0fdac392810ec11555eb0ada69e9d38db3e24809dcefd779d6e71644471e07fc79f2848599fa1e1ba2d7899b1346eb62e778b4f0b88caa8
which = 0021
mac key=EVP_CipherInit_ex(dd,c,key=,iv=,which)
        key= d09e3621be743edfc30db5ba01e4b1dca4791e7d2a8d4f7e0bf9eb6739b27f18
         iv= c79f2848599fa1e1ba2d7899
which = 0021
key=D0 9E 36 21 BE 74 3E DF C3 0D B5 BA 01 E4 B1 DC
A4 79 1E 7D 2A 8D 4F 7E 0B F9 EB 67 39 B2 7F 18

iv=C7 9F 28 48
tls1_enc(0)
EVP_Cipher(ds=02D73CB0,rec->data=02D68058,rec->input=02D68058,l=40) ==>
        EVP_CIPHER_CTX: 0 buf_len, 32 key_len [8 128], 12 iv_len
                IV: C79F28480000000000000000
        rec->input= 44 2e 2c 6c 0a a6 0b 07 da 74 5e 6f 16 56 f5 bc 5b e4 b1 a2 c1 31 66 e8 13 a9 2f d2 79 e8 1a d3 cf 9f a5 88 3f 1d dd df
        rec->data= 14 00 00 0c df 67 a9 c1 b0 47 c5 5f b8 45 d5 f3 13 a9 2f d2 79 e8 1a d3 cf 9f a5 88 3f 1d dd df 06 0c 8e 9e f1 6a d3 ab
dec 16
14 00 00 0C DF 67 A9 C1 B0 47 C5 5F B8 45 D5 F3

tls1_enc(1)
tls1_setup_key_block()
tls1_enc(1)
tls1_change_cipher_state(which= 34) w/
        alg= 1/1, comp= 00000000
        evp_cipher == 0FA8F0B0 ==? &d_cbc_ede_cipher3
        evp_cipher: nid, blksz= 901, 1, keylen=32, ivlen=12
        key_block: len= 88, data= d09e3621be743edfc30db5ba01e4b1dca4791e7d2a8d4f7e0bf9eb6739b27f18c0fdac392810ec11555eb0ada69e9d38db3e24809dcefd779d6e71644471e07fc79f2848599fa1e1ba2d7899b1346eb62e778b4f0b88caa8
which = 0022
mac key=EVP_CipherInit_ex(dd,c,key=,iv=,which)
        key= c0fdac392810ec11555eb0ada69e9d38db3e24809dcefd779d6e71644471e07f
         iv= 599fa1e1ba2d7899b1346eb6
which = 0022
key=C0 FD AC 39 28 10 EC 11 55 5E B0 AD A6 9E 9D 38
DB 3E 24 80 9D CE FD 77 9D 6E 71 64 44 71 E0 7F

iv=59 9F A1 E1
tls1_enc(1)
EVP_Cipher(ds=02D74BB8,rec->data=02D6C5D0,rec->input=02D6C5D0,l=40) ==>
        EVP_CIPHER_CTX: 0 buf_len, 32 key_len [8 128], 12 iv_len
                IV: 599FA1E18597A575CAB57590
        rec->input= 01 00 00 a6 00 00 1c 20 14 00 00 0c ce 42 da 39 00 b7 ed f3 c3 8e 60 b7 f6 0a 49 18 21 3d ed 52 84 d5 b1 8f 0f a5 10 ee
        rec->data= 85 97 a5 75 ca b5 75 90 08 ad 86 3c e0 73 61 37 f1 ba 51 40 69 fe 6e fb f8 ee 13 c0 5b 70 68 ee eb 0c f1 8d d4 7a e2 64
tls1_enc(1)
EVP_Cipher(ds=02D74BB8,rec->data=02D6C5D0,rec->input=02D6C5D0,l=38) ==>
        EVP_CIPHER_CTX: 0 buf_len, 32 key_len [8 128], 12 iv_len
                IV: 599FA1E18597A575CAB57591
        rec->input= 85 97 a5 75 ca b5 75 90 73 65 72 76 65 72 2d 3e 63 6c 69 65 6e 74 6e fb f8 ee 13 c0 5b 70 68 ee eb 0c f1 8d d4 7a
        rec->data= 85 97 a5 75 ca b5 75 91 17 97 78 c4 a4 dc 28 0e 00 09 dd 21 ef 5f 28 c7 19 0a c2 c3 70 bc 9b 11 29 6e ec a0 bf bd
消息'server->client'發送成功,共發送了14個字節!
tls1_enc(0)
EVP_Cipher(ds=02D73CB0,rec->data=02D68058,rec->input=02D68058,l=43) ==>
        EVP_CIPHER_CTX: 0 buf_len, 32 key_len [8 128], 12 iv_len
                IV: C79F2848442E2C6C0AA60B07
        rec->input= 44 2e 2c 6c 0a a6 0b 08 2c c2 3e d4 3b d7 ac f7 26 d7 45 36 10 1d a1 d6 10 cc fd cd 24 8a 50 c7 ff 61 e3 cf a7 11 24 b4 f3 c3 18
        rec->data= 66 72 6f 6d 20 63 6c 69 65 6e 74 2d 3e 73 65 72 76 65 72 cd 24 8a 50 c7 ff 61 e3 cf a7 11 24 b4 f3 c3 18 9e f1 6a d3 ab 0a 80 88
dec 19
66 72 6F 6D 20 63 6C 69 65 6E 74 2D 3E 73 65 72
76 65 72
接收消息成功:'from client->server',共19個字節的數據
tls1_enc(1)
EVP_Cipher(ds=02D74BB8,rec->data=02D6C5D0,rec->input=02D6C5D0,l=26) ==>
        EVP_CIPHER_CTX: 0 buf_len, 32 key_len [8 128], 12 iv_len
                IV: 599FA1E18597A575CAB57592
        rec->input= 85 97 a5 75 ca b5 75 91 01 00 78 c4 a4 dc 28 0e 00 09 dd 21 ef 5f 28 c7 19 0a
        rec->data= 85 97 a5 75 ca b5 75 92 3a 0c 5d d4 0c 9d e9 8b ba 45 d5 39 de 60 47 64 71 b8

可以看出,使用 Debug 版本的 OpenSSL 對於我們調試來說,非常的方便。

 

0x06 調試 OpenSSL 的源代碼

Client 端的源代碼:

// 參考鏈接: https://blog.csdn.net/ljttianqin/article/details/73498453
#include "TLS_Client.h"

#include <WinSock2.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/ssl3.h>

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>

#pragma comment(lib, "WS2_32.lib")

#define MAXBUF 1024

void ShowCerts(SSL * ssl)
{
	X509 *cert;
	char *line;

	cert = SSL_get_peer_certificate(ssl);
	if (cert != NULL) {
		printf("數字證書信息:\n");
		line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
		printf("證書: %s\n", line);
		//free(line);
		line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
		printf("頒發者: %s\n", line);
		//free(line);
		X509_free(cert);
	}
	else
		printf("無證書信息!\n");
}

int main(int argc, char **argv)
{
	int sockfd, len;
	struct sockaddr_in dest;
	char buffer[MAXBUF + 1] = { 0 };
	SSL_CTX *ctx;
	SSL *ssl;
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	SSL_METHOD *method = NULL;
	SSL_CIPHER* cipher = NULL;
	SSL_SESSION *session = NULL;

	/* SSL 庫初始化,參看 ssl-server.c 代碼 */
	SSL_library_init();
	OpenSSL_add_all_algorithms();
	SSL_load_error_strings();
	method = TLSv1_2_client_method();
	ctx = SSL_CTX_new(method);
	if (ctx == NULL) 
	{
		ERR_print_errors_fp(stdout);
	}

	/* 創建一個 socket 用於 tcp 通信 */
	wVersionRequested = MAKEWORD(2, 2);
	err = WSAStartup(wVersionRequested, &wsaData);

	if (err != 0)//返回0表示成功
	{
		return 0;
	}
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
	{
		WSACleanup();
		return 0;
	}

	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		perror("Socket");
		exit(errno);
	}
	printf("socket created\n");

	/* 初始化服務器端(對方)的地址和端口信息 */
	dest.sin_family = AF_INET;
	//dest.sin_addr.s_addr = inet_addr("127.0.0.1");
	//dest.sin_addr.s_addr = inet_addr("localhost");
	//dest.sin_addr.s_addr = inet_addr("192.168.0.123"); // 使用 Npcap Lookback Adapter 只能寫本機IP地址
	dest.sin_addr.s_addr = inet_addr("10.162.143.68");

	dest.sin_port = htons(60005);

	printf("address created\n");

	/* 連接服務器 */
	if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0) 
	{
		perror("Connect ");
		exit(errno);
	}
	printf("server connected\n");

	/* 基於 ctx 產生一個新的 SSL */
	ssl = SSL_new(ctx);
	SSL_set_fd(ssl, sockfd);
	
	// 這裏可以改變默認使用的密碼套件
	
	//err = SSL_set_cipher_list(ssl, "TLS_RSA_WITH_AES_128_GCM_SHA256");
	// 指定使用的密碼套件
	// Wireshark 中顯示的名稱: TLS_RSA_WITH_AES_128_GCM_SHA256
	// 代碼中顯示的名稱:AES128-GCM-SHA256
	//err = SSL_set_cipher_list(ssl, "AES128-GCM-SHA256");
	//if (err)
	//{
	//	puts("Set cipher failed.");
	//}

	/* 建立 SSL 連接 */
	if (SSL_connect(ssl) == -1)
		ERR_print_errors_fp(stderr);
	else 
	{
		printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
		ShowCerts(ssl);
	}
	
	/* 接收對方發過來的消息,最多接收 MAXBUF 個字節 */
	//bzero(buffer, MAXBUF + 1);
	/* 接收服務器來的消息 */
	len = SSL_read(ssl, buffer, MAXBUF);
	if (len > 0)
		printf("接收消息成功:'%s',共%d個字節的數據\n", buffer, len);
	else 
	{
		printf("消息接收失敗!錯誤代碼是%d,錯誤信息是'%s'\n", errno, strerror(errno));
		goto finish;
	}

	//bzero(buffer, MAXBUF + 1);
	memset(buffer, 0, MAXBUF);
	strcpy(buffer, "from client->server");
	/* 發消息給服務器 */
	len = SSL_write(ssl, buffer, strlen(buffer));
	if (len < 0)
		printf("消息'%s'發送失敗!錯誤代碼是%d,錯誤信息是'%s'\n", buffer, errno, strerror(errno));
	else
		printf("消息'%s'發送成功,共發送了%d個字節!\n", buffer, len);

finish:
	/* 關閉連接 */
	SSL_shutdown(ssl);
	SSL_free(ssl);
	closesocket(sockfd);
	SSL_CTX_free(ctx);
	//fclose(fSession);
	return 0;

}

Server 端的源代碼:


// https://blog.csdn.net/ljttianqin/article/details/73498453

#include "TLS_Server.h"


#include <WinSock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#pragma comment(lib, "WS2_32.lib")

#define MAXBUF 1024


int main(int argc, char **argv)
{
	//int sockfd, new_fd;
	SOCKET sockfd, new_fd;
	int len;
	struct sockaddr_in my_addr, their_addr;
	unsigned int myport = 60005, lisnum = 2;
	char buf[MAXBUF + 1];
	SSL_CTX *ctx;
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	SSL_METHOD *method = NULL;
	SSL_CIPHER* cipher = NULL;
	SSL_SESSION *session = NULL;

	/* SSL 庫初始化 */
	SSL_library_init();
	/* 載入所有 SSL 算法 */
	OpenSSL_add_all_algorithms();
	/* 載入所有 SSL 錯誤消息 */
	SSL_load_error_strings();
	/* 以 SSL V2 和 V3 標準兼容方式產生一個 SSL_CTX ,即 SSL Content Text */
	//ctx = SSL_CTX_new(SSLv23_server_method());
	//ctx = SSL_CTX_new(SSLv23_server_method());

	method = TLSv1_2_server_method();
	ctx = SSL_CTX_new(method);
	/* 也可以用 SSLv2_server_method() 或 SSLv3_server_method() 單獨表示 V2 或 V3標準 */
	if (ctx == NULL) {
		ERR_print_errors_fp(stdout);
		exit(1);
	}
	/* 載入用戶的數字證書, 此證書用來發送給客戶端。 證書裏包含有公鑰 */
	if (SSL_CTX_use_certificate_file(ctx, "server.crt", SSL_FILETYPE_PEM) <= 0) 
	{
		ERR_print_errors_fp(stdout);
		exit(1);
	}

	//載入私鑰密碼,否則終端提示用戶手動輸入密碼
	SSL_CTX_set_default_passwd_cb_userdata(ctx, "123456");

	/* 載入用戶私鑰 */
	if (SSL_CTX_use_PrivateKey_file(ctx, "server.key", SSL_FILETYPE_PEM) <= 0) 
	{
		ERR_print_errors_fp(stdout);
		exit(1);
	}
	  
	/*或者
	#include <openssl/ssl.h>
	void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb);
	void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u);
	int pem_passwd_cb(char *buf, int size, int rwflag, void *userdata);
	int pem_passwd_cb(char *buf, int size, int rwflag, void *password)
	{
	strncpy(buf, (char *)(password), size);
	buf[size - 1] = '\0';
	return(strlen(buf));
	}
	*/
	//SSL_CTX_set_default_passwd_cb_userdata(ctx, "123456");

	/* 檢查用戶私鑰是否正確 */
	if (!SSL_CTX_check_private_key(ctx)) 
	{
		ERR_print_errors_fp(stdout);
		exit(1);
	}

	/* 開啓一個 socket 監聽 */
	wVersionRequested = MAKEWORD(2, 2);
	err = WSAStartup(wVersionRequested, &wsaData);
	if (err != 0)
	{
		return 0;
	}
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
	{
		WSACleanup();
		return 0;
	}

	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
	{
		perror("socket");
		exit(1);
	}
	else
		printf("socket created\n");

	my_addr.sin_family = AF_INET;
	my_addr.sin_addr.s_addr = htonl(INADDR_ANY);//inet_addr("10.32.16.174");
	//my_addr.sin_addr.s_addr = inet_addr("192.168.56.1");
	my_addr.sin_port = htons(myport);

	if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1) 
	{
		perror("bind");
		exit(1);
	}
	else
		printf("binded\n");

	if (listen(sockfd, lisnum) == -1) 
	{
		perror("listen");
		exit(1);
	}
	else
		printf("begin listen\n");

	while (1) 
	{
		SSL *ssl;
		len = sizeof(struct sockaddr);

		/* 等待客戶端連上來 */
		if ((new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &len)) == -1) 
		{
			perror("accept");
			exit(errno);
		}
		else
			printf("server: got connection from %s, port %d, socket %d\n",
				inet_ntoa(their_addr.sin_addr),
				ntohs(their_addr.sin_port), new_fd);

		/* 基於 ctx 產生一個新的 SSL */
		ssl = SSL_new(ctx);
		/* 將連接用戶的 socket 加入到 SSL */
		SSL_set_fd(ssl, new_fd);

		// 客戶端或服務端只要有一方指定即可
		//err = SSL_set_cipher_list(ssl, "AES128-GCM-SHA256");
		//if (err)
		//{
		//	puts("Set cipher failed.");
		//}


		/* 建立 SSL 連接 */
		if (SSL_accept(ssl) == -1)
		{
			perror("accept");
			closesocket(new_fd);
			break;
		}

		/* 開始處理每個新連接上的數據收發 */
		//bzero(buf, MAXBUF + 1);
		memset(buf, 0, MAXBUF);
		strcpy(buf, "server->client");
		/* 發消息給客戶端 */
		len = SSL_write(ssl, buf, strlen(buf));

		if (len <= 0) 
		{
			printf
				("消息'%s'發送失敗!錯誤代碼是%d,錯誤信息是'%s'\n",
					buf, errno, strerror(errno));
			goto finish;
		}
		else
			printf("消息'%s'發送成功,共發送了%d個字節!\n",
				buf, len);

		//bzero(buf, MAXBUF + 1);
		memset(buf, 0, MAXBUF);
		/* 接收客戶端的消息 */
		len = SSL_read(ssl, buf, MAXBUF);
		if (len > 0)
			printf("接收消息成功:'%s',共%d個字節的數據\n", buf, len);
		else
			printf ("消息接收失敗!錯誤代碼是%d,錯誤信息是'%s'\n", errno, strerror(errno));
	/* 處理每個新連接上的數據收發結束 */
	finish:
		/* 關閉 SSL 連接 */
		SSL_shutdown(ssl);
		/* 釋放 SSL */
		SSL_free(ssl);
		/* 關閉 socket */
		closesocket(new_fd);
	}

	/* 關閉監聽的 socket */
	closesocket(sockfd);
	WSACleanup();
	/* 釋放 CTX */
	SSL_CTX_free(ctx);
	return 0;

}

 

0x07 調試 OpenSSL 的相關配置

在我們的項目中,使用的是 VS2015,具體配置信息是:

step1: 設置 OpenSSL 頭文件所在路徑

【右鍵項目名稱】->【屬性】->【C/C++】->【常規】->【附加包含目錄】->【填寫 inc32所在的路徑】

在本項目裏,配置如下:

step2: 設置 OpenSSL 庫文件【xxx.lib】所在路徑:

【右鍵項目名稱】->【屬性】->【鏈接器】->【常規】->【附加庫目錄】->【填寫 out32dll.dbg 所在的路徑】

在本項目裏,配置如下:

step3: 設置 OpenSSL 的依賴項【 lib 文件】:

【右鍵項目名稱】->【屬性】->【鏈接器】->【輸入】->【附加依賴項】->【libeay32.lib;ssleay32.lib】

在本項目裏,配置如下:

 

step4: 複製 OpenSSL 的 DLL 文件:

把 OpenSSL 的 DLL 文件複製到我們的工程目錄中,一般是放在 Debug 目錄,不過,如果把 VS 設置成 Release 模式的話,要放到 Release 目錄中,現在我們設置的是 Debug 模式,於是把相應的 DLL 複製到【/Debug】目錄即可,如下圖所示:

客戶端與服務端的配置都一樣,配置好之後就可以編譯調試了。

當然,還需要自己手動去生成一個服務端的證書和密鑰等信息,這裏我就講解了,具體過程可以參考如下鏈接:

https://blog.csdn.net/ljttianqin/article/details/73016014

建議最好在 Linux 上創建這個證書。

這個證書最後需要放在服務端,如下圖所示【注意路徑】:

 

0x08 使用 Wireshark 抓包分析 TLS 協議

由於我的 Client 和 Server 都是在本機上的,所以我們用 Wireshark 抓本機的數據包還需要一些設置,具體請參考以下鏈接:

https://www.cnblogs.com/lvdongjie/p/6110183.html

現在默認你已經可以抓取本機和本機通信的數據包了,現在打開 Wireshark, 點擊 Npcap Loopback Adapter 網卡,如下圖所示:

然後再 過去框中輸入:tcp && ip.addr == 10.162.143.68 , 點擊 Apply【或者直接按回車,新版的 Wireshark 可以直接按回車】,如下圖所示:

然後啓動服務器,等服務器開始監聽端口,如下圖所示:

最後再啓動 客戶端,它們就自動的開始通信了,如下圖所示:

不過要注意設置自己的 Client 的 IP地址爲本機的IP地址,如下圖所示:

最後就可以在Wireshark中看到我們剛纔的通信過程了,如下圖所示:

這個通信的過程包括 TLS 協議的 握手過程 和 數據傳輸 過程。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章