使用OpenSSL程式設計的基本方法
SSL通訊模型為標準的C/S結構,除了在TCP層之上進行傳輸之外,與一般的通訊沒有什麼明顯的區別。在這裡,我們主要介紹如何使用OpenSSL進行安全通訊的程式設計。關於OpenSSL的一些詳細的資訊請參考OpenSSL的官方主頁http://www.openssl.org。
在使用OpenSSL前,必須先對OpenSSL進行初始化,以下的三個函式任選其一:
SSL_library_init(void);
OpenSSL_add_ssl_algorithms();
SSLeay_add_ssl_algorithms();
事實上後面的兩個函式只是第一個函式的巨集。
如果要使用OpenSSL的出錯資訊,使用SSL_load_error_strings(void)進行錯誤資訊的初始化。以後可以使用void ERR_print_errors_fp(FILE* fp)列印SSL的錯誤資訊,也可以使用文獻[2]中的printf("Error: %s\n", ERR_reason_error_string(ERR_get_error()))方法列印資訊。
一次SSL連線會話一般要先申請一個SSL環境,基本的過程是:
1. SSL_METHOD* meth=TLSv1_client_method();建立本次會話連線所使用的協議,如果是客戶端可以使用
SSL_METHOD* TLSv1_client_method(void);TLSv1.0協議
SSL_METHOD* SSLv2_client_method(void);SSLv2協議
SSL_METHOD* SSLv3_client_method(void);SSLv3協議
SSL_METHOD* SSLv23_client_method(void);SSLv2/v3協議
伺服器同樣需要建立本次會話所使用的協議:
SSL_METHOD* TLSv1_server_method(void);
SSL_METHOD* SSLv2_server_method(void);
SSL_METHOD* SSLv3_server_method(void);
SSL_METHOD* SSLv23_server_method(void);
需要注意的是客戶端和伺服器需要使用相同的協議。
2. 申請SSL會話的環境CTX,使用不同的協議進行會話,其環境也是不同的。申請SSL會話環境的OpenSSL函式是
SSL_CTX* SSL_CTX_new(SSL_METHOD*);
引數就是前面我們申請的SSL通訊方式。返回當前的SSL連線環境的指標。然後根據自己的需要設定CTX的屬性,典型的是設定SSL握手階段證書的驗證方式和載入自己的證書。
void SSL_CTX_set_verify(SSL_CTX*, int, int* (int, X509_STORE_CTX*));
設定證書驗證的方式。第一個引數是當前的CTX指標,第二個是驗證方式,如果是要驗證對方的話,就使用SSL_VERIFY_PEER。不需要的話,使用SSL_VERIFY_NONE.一般情況下,客戶端需要驗證對方,而伺服器不需要。第三個引數是處理驗證的回撥函式,如果沒有特殊的需要,使用空指標就可以了。
void SSL_CTX_load_verify_locations(SSL_CTX*, const char*, const char*);
載入證書,第一個引數同上,引數二是證書檔案的名稱,引數三是證書檔案的路徑;
int SSL_CTX_use_certificate_file(SSL_CTX* ctx, const char* file,int type);
載入本地的證書;type指明證書檔案的結構型別;失敗返回-1
int SSL_CTX_use_PrivateKey_file(SSL_CTX* ctx,const char* file,int type);
載入自己的私鑰;type引數指明私鑰檔案的結構型別;失敗返回-1,載入了證書和檔案之後,就可以驗證私鑰和證書是否相符:
int SSL_CTX_check_private_key(SSL_CTX*);
3. 既然SSL使用TCP協議,當然需要把SSLattach到已經連線的套接字上了:
SSL* SSL_new(SSL_CTX*);申請一個SSL套節字;
int SSL_set_rfd(SSL*, int);繫結只讀套接字
int SSL_set_wfd(SSL*, int);繫結只寫套接字
int SSL_set_fd(SSL*, int);繫結讀寫套接字
繫結成功返回1,失敗返回0;
4. 接下來就是SSL握手的動作了
int SSL_connect(SSL*);
失敗返回-1
5. 握手成功之後,就可以進行通訊了,使用SSL_read和SS_write讀寫SSL套接字代替傳統的read、write:
int SSL_read(SSL* ssl, char* buf, int num);
int SSL_write(SSL* ssl, char* buf, int num);
如果是伺服器,則使用SSL_accept代替傳統的accept呼叫
int SSL_accept(SSL* ssl);
6. 通訊結束,需要釋放前面申請的SSL資源
int SSL_shutdown(SSL* ssl);關閉SSL套接字;
void SSL_free(ssl);釋放SSL套接字;
void SSL_CTX_free(ctx);釋放SSL環境;