IKEv2協議幾個問題調試過程以及關鍵知識點總結整理

1. IKEv2基本原理

IKEv2基本原理介紹

2. IKEv2功能遇到的問題

  • 隧道協商速度慢,多條隧道時經常協商不起來
  • 與華爲設備對接IKEv2時,協商報文認證失敗
  • 與華爲設備對接IKEv2時,MD5算法認證失敗(SHA1可以成功情況下)
  • 與華爲設備對接IKEv2時,數據流量不通
  • 與華爲設備對接IKEv2時,IPSec SA配置不同算法時,顯示協商成功,但華爲顯示未成功,數據不通

2.1 問題一:隧道協商速度慢,多條隧道協商時經常協商不起來

①初步分析定位

現象正如問題的描述一樣,僅從現象無法得知導致問題的原因。通過打開pluto調試信息發現協商過程中產生的密鑰長度爲0,密鑰都是空的;對比正常的IPSec協商過程中的調試信息,發現這裏確實存在問題,因此初步確定協商不起來於此有關。當時調試信息基本如下:

... ...
6.26 14:7:36 pluto(52881): KEY length: SK_d=0  SK_ai=0  SK_ar=0  SK_ei=0  SK_er=0  SK_pi=0  SK_pr=0

6.26 14:7:36 pluto(52881): shared:    12 16 4d 32  b8 3e 1e cb  fe c4 08 29  dd 8d 14 31
6.26 14:7:36 pluto(52881):   07 29 0f 14  41 84 ea d3  50 9f ed 43  55 a7 e9 96
6.26 14:7:36 pluto(52881):   a4 16 e6 47  a2 af ed 8b  e4 1e 51 d2  bd 52 49 f0
6.26 14:7:36 pluto(52881):   18 1f d6 66  dd 8c 4e 43  52 78 4e 2a  1d 36 6d f8
6.26 14:7:36 pluto(52881):   b2 2b e2 bd  1e c4 e4 bf  cc 54 dd 99  1b 92 04 4e
6.26 14:7:36 pluto(52881):   dd f5 b1 b3  43 84 df 22  bd e8 ef d3  05 c8 be bf
6.26 14:7:36 pluto(52881): skeyseed:  81 4d 5e 9f  c1 7f 82 5b  75 73 f8 13  da f6 7b 20
6.26 14:7:36 pluto(52881):   3e a0 39 24
6.26 14:7:36 pluto(52881): SK_d:  
6.26 14:7:36 pluto(52881): SK_ai:  
6.26 14:7:36 pluto(52881): SK_ar:  
6.26 14:7:36 pluto(52881): SK_ei:  
6.26 14:7:36 pluto(52881): SK_er: 
6.26 14:7:36 pluto(52881): SK_pi:  
6.26 14:7:36 pluto(52881): SK_pr:  
6.26 14:7:36 pluto(52881): ikev2 parent inI2outR2: calculating g^{xy}, sending R2
6.26 14:7:36 pluto(52881): processing connection IKEv1
6.26 14:7:36 pluto(52881): decrypting as RESPONDER, using INITIATOR keys

②函數調用關係

  • ikev2parent_inI2outR2
    • start_dh_v2
      • send_crypto_helper_request
        • pluto_do_crypto_op
          • case pcr_build_kenonce:
          • case pcr_build_nonce:
          • case pcr_compute_dh_iv:
          • case pcr_compute_dh:
          • case pcr_compute_dh_v2:
            • calc_dh_v2
              • shared
              • skeyseed
              • SK_d
              • SK_ai
              • SK_ar
              • SK_ei
              • SK_er
              • SK_pi
              • SK_pr
        • ikev2_parent_inI2outR2_tail
          • finish_dh_v2
            • st->st_shared
            • st->st_skey_d
            • st->st_skey_ai
            • st->st_skey_ar
            • st->st_skey_ei
            • st->st_skey_er
            • st->st_skey_pi
            • st->st_skey_pr

在這裏插入圖片描述

③問題原因

IKEv2協商使用四個報文兩次交換便完成IPSec隧道的協商建立。前兩個報文用來協商IKE-SA的策略,發起方在收到響應方的應答後進行密鑰的計算,而響應方是在收到發起方第三個報文後再進行各個密鑰的計算生成(也就是ikev2_parent_inI2outR2()中,最終調用calc_dh_v2()完成密鑰生成),之後在ikev2_parent_inI2outR2_tail()中通過finish_dh_v2()將生成的密鑰存儲在state上。

在NGFW支持IKEv2過程中,在pcr_compute_dh_v2()計算密鑰時,IKEv2相關的函數calc_dh_v2()被註釋,從而導致生成的密鑰全部爲空,並最終存到state上的密鑰也是空。因此第二階段的認證加密都會出現問題(有時還會出現段錯誤的問題),但偶爾也能協商成功。修改後隧道便可以正常協商,且支持了多條隧道同時協商。

2.2 問題二和三:與華爲設備對接IKEv2時,協商報文認證失敗

①初步分析定位

在這裏插入圖片描述
通過抓包發現是在收到第三個協商報文後,出現錯誤導致沒有應答報文。打開pluto日誌信息發現時由於認證失敗導致的。而發起方在收到第四個報文後也會出現該問題。下面時發前方收到第四個報文後的信息。

7.1 9:33:7 pluto(49216): ikev2 parent inR2: calculating g^{xy} in order to decrypt I2
7.1 9:33:7 pluto(49216): decrypting as INITIATOR, using RESPONDER keys
7.1 9:33:7 pluto(49216): data being hmac:  65 d0 57 0a  93 0c 90 ac  a9 d9 44 45  75 56 1a f2
7.1 9:33:7 pluto(49216):   2e 20 23 20  00 00 00 01  00 00 00 74  24 00 00 58
7.1 9:33:7 pluto(49216):   ee 58 f5 c7  50 d4 6e 87  db 11 4f 36  b7 e7 92 0c
7.1 9:33:7 pluto(49216):   a3 cb ff e5  54 c3 f1 47  f4 17 ca 2e  26 99 10 c0
7.1 9:33:7 pluto(49216):   d0 90 5a aa  51 33 c0 27  53 6c 36 a3  d9 c0 b8 3b
7.1 9:33:7 pluto(49216):   0f 6c fa a9  4a 9a 7d f6  c3 12 eb 04  04 c6 7e fc
7.1 9:33:7 pluto(49216):   bd 97 f6 4e  79 58 04 39
7.1 9:33:7 pluto(49216): R2 calculated auth:  05 e1 bf 2d  1a ba 0e ea  9a cd 1f 23
7.1 9:33:7 pluto(49216): R2  provided  auth:  f4 17 ca 2e  26 99 10 c0  50 d4 6e 87
7.1 9:33:7 pluto(49216): R2 failed to match authenticator

②函數調用關係

  • ikev2parent_inR2
    • ikev2_decrypt_msg
      • 認證(就是報文的完整性檢查)
        • authkey = &pst->st_skey_ar; 認證密鑰
        • pst->st_oakley.integ_hasher認證算法
        • 實際的報文認證部分; 認證數據
        • 計算哈希值;認證結果
        • 比較收到的認證數據與計算出的數據
      • 解密
        • cipherkey = &pst->st_skey_er;
        • pst->st_oakley.encrypter
        • 從報文中獲取初始向量:IV
        • … …
      • ikev2_process_encrypted_payloads
        • 解析每一個載荷

  • ikev2parent_inR1outI2 或 ikev2_parent_inI1outR1_tail
    • ikev2_parse_parent_sa_body
      • sadb = oakley_alg_makedb(st->st_connection->alg_info_ike;本地策略轉換爲SA
      • sa_v2_convert(sadb); IKEv1 SA轉換爲IKEv2 SA。
      • ikev2_process_transforms; 解析對方的建議載荷
      • ikev2_match_transform_list_parent; 將對端建議載荷與本端配置進行匹配
      • 填充加密算法:ta.encrypter
      • 填充認證算法:ta.integ_hasher
      • 填充PRF算法:ta.prf_hasher
      • 填充DH組:ta.group
      • 將算法存儲到state上:st->st_oakley = ta;

③重點說明

3.1 常用的加解密、認證算法:

這裏需要注意的一點是:完整性檢測算法(認證算法)有兩個標準算法:MD5, SHA1;他們的hash_integ_len是固定的96bits==12Bytes
在這裏插入圖片描述

static struct hash_desc crypto_hasher_md5 =
{
    common: {name: "oakley_md5",
	     officname: "md5",
	     algo_type: IKE_ALG_HASH,
	     algo_id:   OAKLEY_MD5,
	     algo_v2id: IKEv2_PRF_HMAC_MD5,
	     algo_next: NULL, },
    hash_ctx_size: sizeof(MD5_CTX),
    hash_key_size:   MD5_DIGEST_SIZE,
    hash_digest_len: MD5_DIGEST_SIZE,
    hash_integ_len: 0,				/*Not applicable*/
    hash_init: (void (*)(void *)) osMD5Init,
    hash_update: (void (*)(void *, const u_int8_t *, size_t)) osMD5Update,
    hash_final: (void (*)(u_char *, void *)) osMD5Final,
};

static struct hash_desc crypto_integ_md5 =
{
    common: {name: "oakley_md5",
	     officname: "md5",
	     algo_type: IKE_ALG_INTEG,
	     algo_id:   OAKLEY_MD5,
	     algo_v2id: IKEv2_AUTH_HMAC_MD5_96,
	     algo_next: NULL, },
    hash_ctx_size: sizeof(MD5_CTX),
    hash_key_size:   MD5_DIGEST_SIZE,
    hash_digest_len: MD5_DIGEST_SIZE,
    hash_integ_len: MD5_DIGEST_SIZE_96,
    hash_init: (void (*)(void *)) osMD5Init,
    hash_update: (void (*)(void *, const u_int8_t *, size_t)) osMD5Update,
    hash_final: (void (*)(u_char *, void *)) osMD5Final,
};

static struct hash_desc crypto_hasher_sha1 =
{
    common: {name: "oakley_sha",
	     officname: "sha1",
	     algo_type: IKE_ALG_HASH,
	     algo_id:   OAKLEY_SHA,
	     algo_v2id: IKEv2_PRF_HMAC_SHA1,
	     algo_next: NULL, },
    hash_ctx_size: sizeof(SHA1_CTX),
    hash_key_size:   SHA1_DIGEST_SIZE,
    hash_digest_len: SHA1_DIGEST_SIZE,
    hash_integ_len: 0,                          /*Not applicable*/
    hash_init: (void (*)(void *)) SHA1Init,
    hash_update: (void (*)(void *, const u_int8_t *, size_t)) SHA1Update,
    hash_final: (void (*)(u_char *, void *)) SHA1Final,
};

static struct hash_desc crypto_integ_sha1 =
{
    common: {name: "oakley_sha",
	     officname: "sha1",
	     algo_type: IKE_ALG_INTEG,
	     algo_id:   OAKLEY_SHA,
	     algo_v2id: IKEv2_AUTH_HMAC_SHA1_96,
	     algo_next: NULL, },
    hash_ctx_size: sizeof(SHA1_CTX),
    hash_key_size:   SHA1_DIGEST_SIZE,
    hash_digest_len: SHA1_DIGEST_SIZE,
    hash_integ_len: SHA1_DIGEST_SIZE_96,
    hash_init: (void (*)(void *)) SHA1Init,
    hash_update: (void (*)(void *, const u_int8_t *, size_t)) SHA1Update,
    hash_final: (void (*)(u_char *, void *)) SHA1Final,
};
3.2 IKEv1與IKEv2在建議載荷上的區別

IKEv2的建議載荷:
在這裏插入圖片描述
IKEv1的建議載荷:
在這裏插入圖片描述
IKEv1與IKEv2除了載荷類型不同,報文的結構也發生了變化,IKEv2中沒有了屬性載荷,相反IKEv1中的每一個屬性載荷對應IKEv2中的一個變化載荷。因此IKEv2在oakley_alg_makedb()生成SA後需要sa_v2_convert()進行依次格式轉換,轉換爲IKEv2的SA格式。

3.3 關於配置參數問題

3.3.1 IPSec隧道IKE-SA協商階段可以配置的參數:

  • 認證方式:
    • 預共享密鑰
    • 數字證書
  • 加密算法
    • DES
    • 3DES
    • AES
    • SM4
  • 哈希算法
    • MD5
    • SHA1
    • SM3
  • DH組
    • DH1
    • DH2
    • DH5
    • 代碼中的DH包含
enum ike_trans_type_dh {
	OAKLEY_GROUP_MODP768      = 1,
	OAKLEY_GROUP_MODP1024     = 2,
	OAKLEY_GROUP_GP155        = 3,
	OAKLEY_GROUP_GP185        = 4,
	OAKLEY_GROUP_MODP1536     = 5,

	OAKLEY_GROUP_MODP2048     = 14,
	OAKLEY_GROUP_MODP3072     = 15,
	OAKLEY_GROUP_MODP4096     = 16,
	OAKLEY_GROUP_MODP6144     = 17,
	OAKLEY_GROUP_MODP8192     = 18,
#ifdef USE_MODP_RFC5114
	OAKLEY_GROUP_DH22         = 22,
	OAKLEY_GROUP_DH23         = 23,
	OAKLEY_GROUP_DH24         = 24,
#endif
};

3.3.2 IKEv2中PRF算法是怎麼來的:

PRF算法與認證算法都是使用hash進行計算的,NGFW中無法進行單獨配置,而是同時配置兩者保持一致。除此之外:MD5和SHA1算法的值是相同的在PRF算法和完整性算法中

PRF算法包括:

enum ikev2_trans_type_prf {
	IKEv2_PRF_HMAC_MD5      = 1, /* RFC2104 */
	IKEv2_PRF_HMAC_SHA1     = 2, /* RFC2104 */
	IKEv2_PRF_HMAC_TIGER    = 3, /* RFC2104 */
	IKEv2_PRF_AES128_XCBC   = 4, /* RFC4434 */
	IKEv2_PRF_HMAC_SHA2_256 = 5, /* RFC4868 */
	IKEv2_PRF_HMAC_SHA2_384 = 6, /* RFC4868 */
	IKEv2_PRF_HMAC_SHA2_512 = 7, /* RFC4868 */
	IKEv2_PRF_AES128_CMAC   = 8, /* RFC4615 */
	/* 9 - 1023 Reserved to IANA    RFC4306 */
	/* 1024 - 65535 Private Use     RFC4306 */
	IKEv2_PRF_INVALID	= 65536,/*Modify by Sun zhendong for IKEv2 對接華爲設備 at 2020.7.1*/
};

認證算法(完整性算法)包括:

enum ikev2_trans_type_integ {
	IKEv2_AUTH_NONE              = 0,  /* RFC4306 */
	IKEv2_AUTH_HMAC_MD5_96       = 1,  /* RFC2403 */
	IKEv2_AUTH_HMAC_SHA1_96      = 2,  /* RFC2404 */
	IKEv2_AUTH_DES_MAC           = 3,  /* RFC4306 */
	IKEv2_AUTH_KPDK_MD5          = 4,  /* RFC1826 */
	IKEv2_AUTH_AES_XCBC_96       = 5,  /* RFC3566 */
	IKEv2_AUTH_HMAC_MD5_128      = 6,  /* RFC4595 */
	IKEv2_AUTH_HMAC_SHA1_160     = 7,  /* RFC4595 */
	IKEv2_AUTH_AES_CMAC_96       = 8,  /* RFC4494 */
	IKEv2_AUTH_AES_128_GMAC      = 9,  /* RFC4543 */
	IKEv2_AUTH_AES_192_GMAC      = 10, /* RFC4543 */
	IKEv2_AUTH_AES_256_GMAC      = 11, /* RFC4543 */
	IKEv2_AUTH_HMAC_SHA2_256_128 = 12, /* RFC4595 */
	IKEv2_AUTH_HMAC_SHA2_384_192 = 13, /* RFC4306 */
	IKEv2_AUTH_HMAC_SHA2_512_256 = 14, /* RFC4306 */
	/* 15 - 1023 Reserved to IANA         RFC4306 */
	/* 1024 - 65535 Private Use           RFC4306 */
	IKEv2_AUTH_INVALID     =65536
};

④原因分析

  • 問題二是因爲未添加PRF算法導致的
  • 問題三是因爲sa_v2_convert()在轉換SA時,將PRF算法設置爲固定的算法SHA1, 因此當選用MD5時,認證檢測失敗。

2.3 問題四:與華爲設備對接IKEv2時,隧道協商成功,但數據流量不通

①初步分析定位

根據調試信息顯示:數據報文本地解析對端失敗,同時對端華爲設備也無法解析本設備發出的加密報文。追代碼發現IKEv1與IKEv2在隧道協商成功後,使用相同的函數接口將state信息轉換爲IPSecSA,生成sadb和spdb。這裏沒有區別,數據流量流程應該是沒有問題的,因爲IKEv1可以進行數據通信。到這裏最大的可能就是:1)IKEv2協商過程中生成的祕鑰參數信息是否和IKEv1存儲在相同的位置 ; 2)如果不是第一個原因,就需要詳細檢查三四個報文的協商流程。

②函數調用關係

  • ikev2parent_inR2
    • ikev2_decrypt_msg
      • 完整性檢查
        • st->st_oakley.integ_hasher
    • ikev2_decode_peer_id
    • ikev2_decode_local_id
    • PRF計算ID的HASH值
    • v2_AUTH_RSA
      • ikev2_verify_rsa_sha1
    • v2_AUTH_SHARED
      • ikev2_verify_psk_auth
        • ikev2_calculate_psk_sighash
          • get_preshared_secret
          • st->st_oakley.prf_hasher
          • 對端的首包
          • 對端的Nonce載荷數據
          • 對端的ID的哈希值
    • ikev2_child_validate_responder_proposal
    • ikev2_parse_child_sa_body
      • p2alg = kernel_alg_makedb(c->policy , c->alg_info_esp; 根據當前配置生成IPSecSA載荷
      • sa_v2_convert; 將IPSecSA載荷轉換爲IKEv2的格式類型
      • ikev2_process_transforms; 解析對端響應的ipsec-SA的建議載荷
      • ikev2_match_transform_list_child;本端配置和對端選擇的ipsec-SA載荷進行匹配
      • ta.encrypter保存加密算法
      • ta.integ_hash保存完整性檢測算法
      • st->st_esp.attrs.transattrs = ta; 將匹配的算法存儲到state
      • st->st_esp.present = TRUE; 封裝協議標記位
    • ikev2_child_notify_process
    • ikev2_derive_child_keys 最關鍵的生成數據流量祕鑰函數接口
      • childsacalc.prf_hasher
      • childsacalc.ni
      • childsacalc.nr
      • childsacalc.spii
      • childsacalc.spir
      • childsacalc.skeyseed = &st->st_skey_d; 使用了st->st_skey_d
      • st->st_esp.present = TRUE;
      • st->st_esp.keymat_len=enc_len + auth_len;
      • st->st_esp.peer_keymat=v2genbytes(childsacalc, …)
      • st->st_esp.our_keymat=v2genbytes(childsacalc, …)
    • install_ipsec_sa
      • … …

③重點說明

3.1 PRF算法的使用

在IKEv2中PRF算法的應用場景有:

  • 認證數據來源的可靠性

    例如ikev2_calculate_psk_sighash()中使用PRF算法ID共享祕鑰對端首包對端Nonce等對數據報文進行認證,從而確保數據包來源的可靠性。

  • 生成IPSec SA的加密祕鑰和認證祕鑰

    ikev2_derive_child_keys()中,使用PRF算法雙方的Nonce值SPI、以及先前生成的st_skey_d等生成用於數據流量的加密、認證等的祕鑰材料。
    在這裏插入圖片描述

3.2 關鍵名詞

在這裏插入圖片描述

  • 完整性

即對報文的完整性檢查,在ipsec中經常也稱爲認證(authenticator), 它是對整個報文做哈希(準確的說應該不是整個報文),然後將結果添加到報文的末尾。 這個長度目前好像是固定的12字節,即96位(MD5和SHA1都是)。它使用st->st_oakley.integ_hasher進行哈希。見上圖中最後12字節數據。

  • 認證載荷

個人理解認證載荷是爲了保證數據來源的可靠性,一般包括兩種:預共享祕鑰數字證書。它的檢查更爲嚴格,以共享祕鑰爲例:它會對對方的首個報文、Nonce值、ID值同時計算哈希,而不僅僅計算當前報文的內容。認證載荷中填充的數據便是對端對上述內容計算的哈希值。

④原因分析

  • PRF算法是固定的,默認採用了SHA1算法,應該用移植時版本太obsolete的緣故。

2.4 問題五:IPSec SA配置不同算法時,顯示協商成功,流量不通

①初步分析定位

顯示協商成功,實際上只是NGFW上顯示協商成功,華爲設備上顯示並未成功。這個協商不成功的原因是由於第二階段的算法不一致導致的,並且協商時對端的應答報文中給出相應的原因。但是由於NGFW的IKEv2現階段並未處理INFORMATION載荷,因此誤認爲對端接受了本端的提議,從而顯示協商成功。但由於應答報文中沒有建議載荷,從而本端並未生成Ipsec SA,數據流量因此無法通訊;如果對當前的隧道進行操作,在刪除當前隧道的狀態、sadb等時由於sadb中的相關參數爲空導致pluto進程異常退出。
在這裏插入圖片描述

②其他

略。

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