再談SSL和OpenSSL
- 由于SSL協議已經是密碼學和PKI技術中非常具體的一個應用協議,為了實現它,OpenSSL在密碼學基礎應用和PKI技術的基礎實現上做了大量的工作,才逐漸形成和奠定了OpenSSL在密碼學應用和PKI技術開發中的重要基礎軟件包地位。
- OpenSSL涉及到SSL協議的實現、協議的應用和協議的開發調試等多個方面。
- 本章將主要從應用層面上來對SSL協議進行闡述,這僅是OpenSSL提供的SSL支持的一部分內容,OpenSSL還提供了基于SSL開發API等更多具有重要價值的資料,但并未涉及。
- OpenSSL提供了四個直接的SSL相關指令:s_client,s_server,s_time和sess_id,這些指令可以模擬SSL客戶端和服務器端的多種動作和環境,用于測試和分析現有的SSL服務器或者客戶端的運行狀況,也可以將這些源代碼作為實現SSL客戶端或者服務器的參考。
用s_client指令模擬SSL客戶端
功能概述和指令格式
- s_client指令模擬了一個通用的SSL/TLS客戶端。事實上,為了調試的目的,它比一般的SSL客戶端實現復雜得多。你可以用s_client連接各種SSL服務器,如果你要連接一個HTTPS服務器(HTTS服務端口是443),輸入下面的口令就可以:
- ?一旦s_client和某個SSL服務器的連接建立成功,那么服務器所有傳送過來的信息都會被顯示出來,而客戶端的所有鍵盤輸入也會被發送給服務器。
- 下面通過對s_client指令各個參數的介紹來全面了解該指令的功能。
- 首先看看s_client指令的格式:
- 服務地址選項connect,host和port作為一個SSL模擬客戶端,要運行的時候,首先當然需要指定SSL服務器的地址和服務端口。
- connect選項指定了連接的主機地址和服務端口,其參數形式如下
- 其中,host可以為IP地址,也可以為URL;
- port為服務端口。事實上,你還可以使用兩個很少使用的host和port選項來分別指定服務地址和服務端口,如下面的指令:?
- ?如果上述選項都沒有使用,那么默認建立的連接為本地主機的4433端口。
客戶端證書選項cert和key
- cert選項指定客戶端要使用的證書文件,該文件包含的證書僅在SSL服務器明確提出要求驗證客戶端證書的時候會被使用,否則該證書沒有任何用處,cert選項也完全可以省略。
- key選項則指定了客戶端證書相應的私鑰文件,如果使用了cert選項而沒有使用該選項,那么指令會試圖從cert指定的證書存儲文件中讀取私鑰。當服務器要求進行客戶端證書驗證的時候,最常見到的錯誤就是聲稱客戶端沒有用戶證書或者說提供的證書列表文件是空的(當然,你很有信心,你提供的證書文件絕對是包含一個證書的)。
- 這種情況出現的原因,一般是因為服務器在要求客戶端證書驗證的時候發送過來的信任CA證書列表里面不包含簽發你所提供的客戶證書的CA證書。
- 使用s_client指令,你可以查看到SSL服務器支持的CA列表。不過,有些SSL服務器只會在客戶端訪問某些頁面的時候才要求進行客戶端證書驗證,這時候,為了看到其支持的CA證書列表,可以使用prexit選項將SSL連接過程中的所有信息打印處理。
驗證服務器選項verify,CApath,CAfile,crl_check和crl_check_all
- SSL支持雙向的證書驗證,也就是說,不僅僅服務器可以驗證客戶端的身份,客戶端也可以驗證服務器的身份。事實上,在目前的運用中,更常見的是客戶端對服務器身份的驗證。
- 使用verify選項后,將啟動SSL模擬客戶端對SSL服務器證書的驗證過程,同時,verify的參數設定了證書驗證的深度,超過此深度,即視為證書驗證失敗。所謂證書驗證深度,就是證書鏈(這里指服務器證書的證書鏈)的長度,即從根CA到服務器證書的層數,如果簽發服務器證書的CA本身就是根CA,那么證書鏈長度就為1。
- 需要注意的是,由于s_client僅僅是一個SSL客戶端模擬程序,為了能充分顯示出SSL連接過程中所有可能出現的問題,當驗證服務器證書的過程中碰到錯誤或者應當視為驗證失敗的情況下,s_client程序也不會中斷連接,而是會繼續工作下去,當然,它會將所有錯誤信息忠實地輸出來。所以,s_client程序永遠不會因為驗證服務器證書失敗而終止運行。
- CApath選項指定了存放用于驗證服務器證書時使用的候選信任CA證書標準目錄。在需要建立客戶端的證書鏈時,該目錄存放的證書也可能被使用。
- CAfile選項則指定了一個存放一系列信任CA證書的文件,這些證書在驗證服務器證書的時候需要使用。此外,當需要建立客戶端的證書鏈時,這個文件中存放的CA證書也可能被使用。
- crl_check選項告訴指令要同時檢查服務證書在CRL列表中的狀態
- crl_check_al則告訴指令要檢查整個服務器證書鏈中每一個證書在CRL列表中的狀態。
- CRL由cert指令指定的文件輸入。
顯示信息和狀態選項showcerts,prexit,state,msg,debug和quiet
- 默認情況下,s_client指令僅輸出服務器的證書,如果使用了showcerts選項,則將顯示服務器的整個證書鏈。在你驗證服務器證書碰到問題時,可以使用該選項來診斷是否是證書原因。
- 使用prexit選項后,無論SSL連接是否建立成功,當程序退出時都會試圖輸出所有會話(Sesion)信息。而一般情況下,僅在連接建立成功的時候,s_client選項才會輸出會話信息。在以下幾種SSL連接曾經成功建立的情況下,prexit選項對診斷SSL連接狀態非常有用:
- 1? 使用的加密算法需要重新協商;
- 2? 因為需要對客戶端證書進行驗證導致SSL連接建立失敗;
- 3? 在訪問特定URL的時候要求進行客戶端證書驗證導致連接建立失敗。
- 當然,prexit選項輸出的信息有時候不一定非常準確,因為有時候SSL連接可能從來就沒有成功建立過,這時候輸出的會話信息自然就沒有任何意義。
- state選項告訴指令輸出SSL連接會話(Sesion)狀態。
- msg選項告訴指令以十六進制編碼的格式輸出所有協議相關的信息。
- debug選項告訴指令輸出所有的調試信息,并將所有的通信數據以十六進制編碼的格式輸出。
- quiet選項告訴指令不要輸出所有會話和證書信息,同時,該選項會默認打開ign_eof這個選項。
socket連接方式選項nbio_test和nbio
- nbio_test選項告訴指令對非阻塞SSL通信socket進行更多的測試檢查。
- nbio選項告訴指令使用非阻塞socket進行SSL通信。
連接動作選項pause,reconnect,starttls和ign_eof
- 使用pause選項后,指令在每次讀或者寫操作之后都會暫停一秒鐘。
- reconnect選項主要用于測試服務器會話緩存功能是否有效,使用該指令后,s_client會使用同一個會話(Sesion)反復連接相同的SSL服務器5次。有些應用協議支持TLS協議,但是必須在建立協議連接之后輸入一個STARTTLS指令才能開始建立TLS連接的動作,s_client指令為了支持這種協議形式,增加了startls選項。
- startls選項的參數是要建立連接的協議代碼,目前僅支持“smth”協議,相信以后會慢慢完善和增加的(最新的版本已經增加了pop3協議)。
- ign_eof選項告訴指令當輸入文件到達文件尾(遇到文件結束符)時保持連接。如果不啟用ign_eof選項(或者quiet選項),s_client指令跟服務器的連接建立后就處于交換模式,這時候還可以輸入幾個簡單的指令來調整連接的狀態,目前支持的指令包括:
- 1? R,會話重新協商,即在行開始第一個字母輸入“R”的時候,SSL當前的會話進行重新協商,采用新的會話;
- 2? Q,斷開連接,即在行開始第一個字母輸入“Q”的時候,SSL當前連接立即斷開,結束s_client指令。
- 事實上,當輸入到達文件尾(文件結束符)的時候,一樣會斷開連接。
?協議版本選項ssl2,ssl3,tls1,no_ssl2,no_ssl3和no_tls1
- 這些選項告訴指令選擇用什么版本的協議建立SSL連接。默認的情況下,SSL客戶端支持所有版本協議,包括SSL2.0,SSL3.0和TLS1.0,并自動選擇協商合適的協議建立連接。但是有些SSL服務器的實現并不規范,所以不一定能支持所有協議,并且會要求一定要不支持某種協議(如TLS1.0)才能夠建立連接。
- 使用ssl2,ssl3或者tls1選項是告訴指令只使用指定的版本協議,放棄其他協議。如果這幾個選項同時使用,那么只有最后一個選項才會有效。
- no_ssl2,no_ssl3和no_tls1選項則告訴指令放棄某種指定的協議。
密碼算法選項cipher和serverpref
- SSL客戶端和服務器建立連接的時候,需要協商一組密碼算法,用戶通信加密和數據完整性保證等,通常情況下,服務器會從客戶端發送過來的所有支持的密碼算法組中選擇第一組(服務器當然也必須支持該組算法)作為雙方通信使用的算法。
- 有時候可能你希望使用某組特定的算法,這時候就可以使用cipher選項來指定。關于cipher參數的具體信息,請參考本書相關章節的內容。
- serverpref選項僅對SSL2.0協議有效,它告訴指令使用SSL服務器指定的算法來建立連接。
其他選項bugs,crlf,rand和engine
- SSL/TLS有幾個眾所周知的實現上的BUG,s_client指令提供bugs選項來適應存在這些BUG的服務器。
- crlf選項把終端輸入的換行回車符轉化成/r/n發送給SSL服務器,某些服務器有這樣的特殊需求。
- rand選項指定了用于產生隨機數種子的文件,這跟其他指令的同名選項是一樣的,這里不再多作介紹。
- engine選項則告訴指令使用指定的Engine設備,參數是Engine設備的ID號。?
例子?
SSL服務器性能測試指令s_time
功能概述和指令格式
- OpenSSL提供了另外一個與s_client相似的SSL客戶端模擬程序s_time,不同的是,該程序主要用來測試SSL服務器的性能。
- s_time程序通過從服務器下載一個頁面,通過測試其傳輸的數據和花費的時間來測試SSL服務器性能,其測試的項目包括:
- 1? ?給定時間段內建立的連接數量;
- 2? ?傳輸的數據量;
- 3? ?計算每個連接平均花費時間。
- 下面是s_time指令的選項和格式:
網頁內容選項www
- www選項的參數指定了要從SSL服務器上獲取(GET動作)的網頁名稱,例如“default.asp”這樣的網頁文件名。如果該選項沒有定義,那么s_time指令只是完成握手建立連接,但是不傳輸任何應用數據。
連接會話選項new和reuse
- new選項告訴s_time指令每次建立新SSL連接的時候都使用新的會話(Sesion)ID。
- reuse選項則告訴s_time指令每次建立新SSL連接的時候使用相同的會話(Sesion)ID。
- 這可以用來測試SSL服務器的會話緩存功能的工作狀態是否正常。如果上述兩個選項都沒有使用,那么指令會默認將兩個選項都打開,并交替執行這兩個選項定義的內容。也就是說在建立新SSL連接的時候,指令一會兒用新的會話ID,一會兒重用上次會話ID。
連接時間選項time
- 選項time告訴指令統計在該選項參數指定的時間內(單位是秒)s_time和SSL服務器能夠建立連接并從服務器傳輸指定數據(如果www指定了頁面)的次數。當然,最后測試結果出來的時間不一定正好是指定的時間,因為指令必須在等待一個完整的連接動作完成后才能夠結束并給出結果。?
例子
SSL客戶端分析?
- OpenSSL同樣很負責任地提供了s_server指令,用于模擬一個通用的而且負責的SSL服務器,目的就是為了能夠對SSL客戶端進行測試。
- s_server指令不僅僅模擬了一個完整通用的SSL服務器,并且還在此基礎上模擬了一個Web服務器,提供Web服務。
- 下面是s_server指令的選項和格式:
?監聽端口選項accept
- accept選項指定SSL服務端口,在默認的情況下指令將使用4433端口。
證書和私鑰選項cert,key,dcert,dkey和nocert
- cert選項指定服務器使用的證書。大部分服務器算法簇的運行需要數字證書,而且有些還需要特定類型公鑰的證書。例如在DSS算法簇中就需要一個包含了DSS(DSA)密鑰的證書。cert選項如果沒有定義,默認情況下將使用server.pem文件中的證書。key選項指定存儲私鑰的文件,該私鑰和cert選項指定的證書應該是相對應的,如果本選項沒有出現,那么cert選項定義的證書文件會被認為同時也是存儲私鑰的文件。正如前面所說,在SSL協議的算法簇中,不同的算法可能需要不同密鑰類型的證書來進行服務器驗證。
- 例如,RSA算法簇需要RSA密鑰證書來完成SSL連接的建立,而DSA算法簇則需要DSA密鑰證書來完成SSL連接的建立過程。所以,為了使得SSL服務器能夠兼容各種不同客戶端的需要,可能需要在服務器端提供不同類型的證書以備選用,這就是下面dcert和dkey選項出現的原因。
- dcert和dkey這兩個選項用于在cert跟key選項之外再指定一個附加的證書文件和私鑰文件,它們的用法跟cert和key選項是相同的,不過,dcert和dkey選項沒有默認值。因為我們的服務器需要支持不同的組合密碼,而不同的組合密碼需要不同的證書和私鑰文件。
- 不同的組合密碼在這里主要是指組合密碼里面的不對稱加密算法不同。比如基于RSA的組合密碼需要的是RSA的私鑰文件和證書;而基于DSA算法的,則需要的是DSA的私鑰文件和證書,使用這兩個選項,就使得我們的服務器同時支持兩種不同的組合密碼成為可能。nocert選項告訴服務器不使用證書進行SSL連接的建立,這樣的直接后果就是造成需要使用證書的SSL算法簇不能使用,即SSL服務器將僅支持匿名的DH算法進行SSL連接建立。不過,目前有些瀏覽器(如IE和Netscape)僅支持基于RSA算法證書的SSL算法簇,如果SSL服務器不支持RSA算法,則將導致SSL連接建立失敗。
DH參數選項dhparam和no_dhe選項
- dhparam指定一個DH參數文件。DH密碼簇在使用的時候需要一組DH參數來產生私鑰。如果沒有指定DH參數文件,當使用DH算法的時候,那么服務器首先會嘗試從服務器證書文件里面獲得DH參數;
- 如果證書文件里面沒有DH參數,那么s_server指令程序代碼中的一組固定DH參數將會被使用。
- no_dhe選項告訴s_server指令禁止一切的DH參數的調用,此時,DH算法簇將不會在SSL連接中被使用。
證書驗證選項verify,Verify,CApath和CAfile
- 選項verify要求客戶端發送證書進行驗證,同時其參數設置了客戶端證書鏈最大的驗證深度。但是,對于客戶端來說,這僅是一個可選的動作,客戶端如果不發送證書給服務器進行驗證,也可以順利建立SSL連接。
- 而如果使用Verify選項表示客戶端必須發送一個證書進行驗證,否則SSL握手將失敗。
- 選項CApath指定了服務器存放可信任證書文件的目錄,這些證書文件在對客戶端證書驗證的時候需要使用,此外,在要求建立服務器證書鏈的時候,目錄中的這些證書也有可能被使用。
- 選項CAfile指定一個存儲證書的文件,該文件包含了服務器信任的CA證書,跟CApath一樣,這些證書在進行客戶端證書驗證的時候需要使用,在建立服務器證書鏈的時候也可能被使用。此外,客戶端進行SSL握手要求客戶端發送用戶證書時,這些證書將作為服務器可接受的信任CA列表發送給客戶端。
- 如果服務器端發送一個空的信任CA列表給客戶端(比如沒有定義CAfile文件),雖然理論上應該是違反協議規定的,但很多SSL客戶端認為這時候服務器能夠接受任何CA簽發的證書,這在調試程序的時候可能反而會有些幫助。
Web服務器模擬選項www,WWW和HTTP
- 使用www選項后,當SSL客戶端連接上SSL服務器的時候,將接收到服務器發回的一些狀態信息。這些狀態信息包括連接使用的算法和會話參數等,并且被格式化成HTML的格式,所以,經常可以被Web瀏覽器SSL客戶端接受和解釋。
- 使用WWW選項服務器端將模擬一個簡單的Web服務器。指令程序所在的目錄將被解釋成網頁的當前目錄。例如如果客戶端的URL請求是htps://myhost/page.html,服務器將把./page.html發回給客戶端。
- HTTP選項跟WWW選項的功能基本上是一樣的,唯一的區別是,使用HTTP選項后,當前目錄中所有被請求的文件,都假定是符合HTTP格式的文件。而選用WWW選項則s_server在發送被請求的文件給客戶端之前,會根據后綴名判斷被發送的文件是普通文件還是HTTP文件,并告知客戶端。
- 如果上述三個選項都沒有使用,當一個SSL客戶端成功連接到服務器后,客戶端所發送過來的任何數據都會在服務器端顯示出來,服務器端任何鍵盤輸入也都會被發送給客戶端。此時,一些單個的特殊字符在指令行可以輸入,以達到一些特殊的目的,支持的字符指令及其含義如表12-1所示。
其他選項context,no_tmp_rsa,id_prefix和hack
- context選項用于設置SSL結構體的ID,可以設置為任何值,如果不設置,將使用默認值。
- 某些算法簇會要求使用一個臨時的RSA密鑰,no_tmp_rsa選項將禁止臨時RSA密鑰的產生。
- id_prefix選項指定SSL/TLS所有會話ID的前綴。這個功能在測試多個SSL服務器的時候會非常有用(比如通過SSL代理的方式),每個服務器都會產生特定范圍的會話ID,方便識別和調試。
- hack選項是為了兼容早期版本的Netscape瀏覽器,一般來說使用很少。?
例子
- 下面的例子必須在s_server程序的目錄下放一個server.pem的文件,文件應該存有一個服務器數字證書和其相應的私鑰,否則將出錯。
- 該程序模擬了一個SSL服務器和Web服務器:?
SSL會話深入分析
- 在使用s_client或者s_server指令的debug選項進行調試的時候,通常會看到其中包括一段諸如下面的內容:
- 這就是SSL會話(Sesion)結構的PEM編碼,你可能看不懂上述這些不知所云的PEM編碼內容。但是,分析一個SSL連接中所有會話的實際內容對于我們分析SSL連接及調試程序都是非常有用的,所以OpenSSL提供了一個翻譯工具,幫助我們讀懂上面的內容。
- 所以,上面的方法,就是獲取編碼SSL會話結構的一種途徑和需要之一。
?功能概述和指令格式
- OpenSSL提供的ses_id指令就是用于處理保存下來的SSL會話(Sesion)編碼結構,根據指令選項要求打印出其中的信息。
- ses_id一般作為一個調試工具使用,并需要用到SSL協議的相關知識,這聽起來有些難度,不過,幸運的是,很少用戶會用到這個指令。其指令格式為:
?輸入和輸出格式選項inform和outform
- 跟其他指令一樣,這兩個選項分別指定了輸入和輸出格式,其中,outform指定的也是輸出編碼會話(Sesion)結構的格式,不會影響其他可讀內容的輸出格式。目前支持的格式包括DER和PEM,默認是PEM格式。
- PEM格式的SSL會話包含在一個固定結構中,第一行和最后一行格式如下:
?輸入和輸出文件選項in和out
- in和out選項指定了輸入和輸出文件名,輸入文件一般存儲的是一個編碼SSL會話結構,輸出文件則輸出SSL會話信息(也包括SSL的編碼會話結構)。默認情況下是標準輸入和輸出設備。
輸出內容選項text,noout和cert
- 選項text將告訴指令對SSL會話結構進行完全的明文解釋,輸出所有可能的內容,其輸出的信息典型如下面所示:
- 當SSL會話結構中包含證書時,cert選項告訴指令輸出該證書結構,如果同時還使用text選項,那么將輸出證書的可讀形式。
- 一般情況下,sess_id指令最后都會輸出SSL會話的編碼結構,使用noout選項后,將只輸出text選項或者cert選項要求輸出的內容,而不再輸出SSL會話的編碼結構。
其他選項context
- context選項用來指定一個特殊的ID替換編碼里面的ID作為輸出的會話ID,這個ID可以為任意字符串。