1. 程式人生 > >修改 OpenVPN 實現加密演算法的自動協商

修改 OpenVPN 實現加密演算法的自動協商

另一篇博中的分析可知,OpenVPN 中有兩個加解密通道。一條是標準的 SSL 協議通道,被 OpenVPN 用於協商自己所用的金鑰。這個通道的加密演算法當然也是通過 SSL 協議來進行協商的,可以通過 --tls-cipher 選項來進行配置。另一條是 OpenVPN 自己的加解密通道,用於交換實際的資料,也就是虛擬網絡卡抓到的 IP 報文。這個通道的加密演算法則是通過 --cipher--auth 兩個選項,分別在通調兩端指定的。

對於第二條通道的加密演算法,必須要同時在兩端分別指定一致的選項,有時候不是很方便(當然,我研究的還是 2.1.1 版本的 OpenVPN ,不知道最新的版本還是不是這樣)。比如說,我想通過在服務端修改配置,指定加密演算法,然後讓連線我的客戶端自動用同一個演算法。最簡單的修改思路,就是借用第一條通道中的演算法協商機制,從 SSL 物件中取得協商出來的演算法。

具體做法就是:

首先,在函式 do_init_crypto_tls_c1() 中,去掉對函式 init_key_type() 的呼叫。這個呼叫就是根據 --cipher--auth 選項進行演算法配置的地方,我們要動態協商,自然是不需要這個了。

但同時,這會引起接下來一個步驟的錯誤。在函式 crypto_adjust_frame_parameters() 中,會根據之前配置的演算法進行報文中金鑰空間的分配。現在還不知道演算法,怎麼知道要分配多少空間呢?就只能改成最大值了。分別改為 MAX_CIPHER_KEY_LENGTHMAX_HMAC_KEY_LENGTH 就行了。當然,這樣改不僅浪費空間,而且也不夠嚴謹,因為 key length 和 IV length 不是一回事,卻只能都用 MAX_CIPHER_KEY_LENGTH

來初始化。

最後就是在 SSL 協商好之後,從裡面取加密演算法了。具體位置在 key_method_2_write()key_method_2_read() 兩個函式中,對 generate_key_expansion() 函式的呼叫之處了。在呼叫之前,初始化一下 key_type 就行了:

1
2
3
4
5
6
7
8
9
struct key_type *key_type = (struct key_type *) session->opt->key_type;
key_type->cipher = ks->ssl->enc_read_ctx
->cipher;
key_type->cipher_length = EVP_CIPHER_key_length (session->opt->key_type->cipher); #if OPENSSL_VERSION_NUMBER >= 0x010000000L key_type->digest = ks->ssl->read_hash->digest; #else key_type->digest = ks->ssl->read_hash; #endif key_type->hmac_length = EVP_MD_size (session->opt->key_type->digest);

這樣就行了。