Linux内核中的IPSEC实现(6)

146 篇文章 12 订阅
81 篇文章 0 订阅
Java代码   收藏代码
  1. 8. 安全协议  
  2.   
  3. 与IPSEC相关的安全协议是AH(51)和ESP(50), IPSEC使用这两个协议对普通数据包进行封装, AH只认证不加密, ESP既加密又认证, 当ESP和AH同时使用时, 一般都是先进行ESP封装, 再进行AH封装, 因为AH是对整个IP包进行验证的, 而ESP只验证负载部分.  
  4.   
  5. 在IPV4下的AH和ESP的协议实现在net/ipv4/ah4.c和net/ipv4/esp4.c中, 每个协议实现实际是要完成两个结构: struct net_protocol和struct xfrm_type, 前者用于处理接收的该协议类型的IP包, 后者则是IPSEC协议处理.  
  6.   
  7. 8.1 AH  
  8.   
  9. 8.1.1 初始化  
  10.   
  11. /* net/ipv4/ah4.c */  
  12. static int __init ah4_init(void)  
  13. {  
  14. // 登记AH协议的xfrm协议处理结构  
  15.  if (xfrm_register_type(&ah_type, AF_INET) < 0) {  
  16.   printk(KERN_INFO "ip ah init: can't add xfrm type\n");  
  17.   return -EAGAIN;  
  18.  }  
  19. // 登记AH协议到IP协议  
  20.  if (inet_add_protocol(&ah4_protocol, IPPROTO_AH) < 0) {  
  21.   printk(KERN_INFO "ip ah init: can't add protocol\n");  
  22.   xfrm_unregister_type(&ah_type, AF_INET);  
  23.   return -EAGAIN;  
  24.  }  
  25.  return 0;  
  26. }  
  27.   
  28. 8.1.2 IPV4下的AH协议处理结构  
  29.   
  30. // AH协议处理结构, 接收到IPV4包后, 系统根据IP头中的protocol字段选择相应的上层协议处理  
  31. // 函数, 当IP协议号是51时, 数据包将调用该结构的handler处理函数:  
  32. static struct net_protocol ah4_protocol = {  
  33.  .handler = xfrm4_rcv,  
  34.  .err_handler = ah4_err,  
  35.  .no_policy = 1,  
  36. };  
  37. AH协议结构的handler函数为xfrm4_rcv, 在net/ipv4/xfrm4_input.c 中定义, 在上一篇中进行了介绍.  
  38.   
  39. // 错误处理, 收到ICMP错误包时的处理情况, 此时的skb包是ICMP包  
  40. static void ah4_err(struct sk_buff *skb, u32 info)  
  41. {  
  42. // 应用层, data指向ICMP错误包里的内部IP头  
  43.  struct iphdr *iph = (struct iphdr*)skb->data;  
  44. // AH头  
  45.  struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+(iph->ihl<<2));  
  46.  struct xfrm_state *x;  
  47. // ICMP错误类型检查, 本处理函数只处理"目的不可达"和"需要分片"两种错误  
  48.  if (skb->h.icmph->type != ICMP_DEST_UNREACH ||  
  49.      skb->h.icmph->code != ICMP_FRAG_NEEDED)  
  50.   return;  
  51. // 重新查找SA  
  52.  x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET);  
  53.  if (!x)  
  54.   return;  
  55.  printk(KERN_DEBUG "pmtu discovery on SA AH/%08x/%08x\n",  
  56.         ntohl(ah->spi), ntohl(iph->daddr));  
  57.  xfrm_state_put(x);  
  58. }  
  59.   
  60. 8.1.3 AH4协议的IPSEC处理结构  
  61.   
  62. // AH4的xfrm协议处理结构  
  63. static struct xfrm_type ah_type =  
  64. {  
  65.  .description = "AH4",  
  66.  .owner  = THIS_MODULE,  
  67.  .proto       = IPPROTO_AH,  
  68. // 状态初始化  
  69.  .init_state = ah_init_state,  
  70. // 协议释放  
  71.  .destructor = ah_destroy,  
  72. // 协议输入  
  73.  .input  = ah_input,  
  74. // 协议输出  
  75.  .output  = ah_output  
  76. };  
  77. 结构的重点是input和ouput函数  
  78.   
  79. 8.1.3.1 状态初始化  
  80. ah_data数据结构:  
  81. /* include/net/ah.h */  
  82. struct ah_data  
  83. {  
  84. // 密钥指针  
  85.  u8   *key;  
  86. // 密钥长度  
  87.  int   key_len;  
  88. // 工作初始化向量  
  89.  u8   *work_icv;  
  90. // 初始化向量完整长度  
  91.  int   icv_full_len;  
  92. // 初始化向量截断长度  
  93.  int   icv_trunc_len;  
  94. // HASH算法  
  95.  struct crypto_hash *tfm;  
  96. };  
  97.   
  98. // 该函数被xfrm状态(SA)初始化函数xfrm_init_state调用  
  99. // 用来生成SA中所用的AH数据处理结构相关信息  
  100. static int ah_init_state(struct xfrm_state *x)  
  101. {  
  102.  struct ah_data *ahp = NULL;  
  103.  struct xfrm_algo_desc *aalg_desc;  
  104.  struct crypto_hash *tfm;  
  105. // 对AH协议的SA, 认证算法是必须的, 否则就没法进行AH认证了  
  106.  if (!x->aalg)  
  107.   goto error;  
  108.  /* null auth can use a zero length key */  
  109. // 认证算法密钥长度要大于512  
  110.  if (x->aalg->alg_key_len > 512)  
  111.   goto error;  
  112. // 如果要进行UDP封装(进行NAT穿越), 错误, 因为AH是不支持NAT的  
  113.  if (x->encap)  
  114.   goto error;  
  115. // 分配ah_data数据结构空间  
  116.  ahp = kzalloc(sizeof(*ahp), GFP_KERNEL);  
  117.  if (ahp == NULL)  
  118.   return -ENOMEM;  
  119. // 设置AH数据结构的密钥和长度  
  120.  ahp->key = x->aalg->alg_key;  
  121.  ahp->key_len = (x->aalg->alg_key_len+7)/8;  
  122. // 分配认证算法HASH结构指针并赋值给AH数据结构  
  123. // 算法是固定相同的, 但在每个应用使用算法时的上下文是不同的, 该结构就是描述具体应用  
  124. // 时的相关处理的上下文数据的  
  125.  tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC);  
  126.  if (IS_ERR(tfm))  
  127.   goto error;  
  128.  ahp->tfm = tfm;  
  129. // 设置认证算法密钥  
  130.  if (crypto_hash_setkey(tfm, ahp->key, ahp->key_len))  
  131.   goto error;  
  132.    
  133.  /* 
  134.   * Lookup the algorithm description maintained by xfrm_algo, 
  135.   * verify crypto transform properties, and store information 
  136.   * we need for AH processing.  This lookup cannot fail here 
  137.   * after a successful crypto_alloc_hash(). 
  138.   */  
  139. // 分配算法描述结构  
  140.  aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);  
  141.  BUG_ON(!aalg_desc);  
  142.  if (aalg_desc->uinfo.auth.icv_fullbits/8 !=  
  143.      crypto_hash_digestsize(tfm)) {  
  144.   printk(KERN_INFO "AH: %s digestsize %u != %hu\n",  
  145.          x->aalg->alg_name, crypto_hash_digestsize(tfm),  
  146.          aalg_desc->uinfo.auth.icv_fullbits/8);  
  147.   goto error;  
  148.  }  
  149. // AH数据结构的初始化向量的总长和截断长度的赋值   
  150.  ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8;  
  151.  ahp->icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8;  
  152.    
  153.  BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN);  
  154. // 分配初始化向量空间, 没对其赋值, 其初始值就是随机值, 这也是初始化向量所需要的  
  155.  ahp->work_icv = kmalloc(ahp->icv_full_len, GFP_KERNEL);  
  156.  if (!ahp->work_icv)  
  157.   goto error;  
  158. // AH类型SA中AH头长度: ip_auth_hdr结构和初始化向量长度, 按8字节对齐   
  159. // 反映在AH封装操作时要将数据包增加的长度  
  160.  x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len);  
  161. // 如果是通道模式, 增加IP头长度  
  162.  if (x->props.mode == XFRM_MODE_TUNNEL)  
  163.   x->props.header_len += sizeof(struct iphdr);  
  164. // SA数据指向AH数据结构  
  165.  x->data = ahp;  
  166.  return 0;  
  167. error:  
  168.  if (ahp) {  
  169.   kfree(ahp->work_icv);  
  170.   crypto_free_hash(ahp->tfm);  
  171.   kfree(ahp);  
  172.  }  
  173.  return -EINVAL;  
  174. }  
  175.   
  176. 8.1.3.2 协议释放  
  177. // 该函数被xfrm状态(SA)释放函数xfrm_state_gc_destroy()调用  
  178. static void ah_destroy(struct xfrm_state *x)  
  179. {  
  180.  struct ah_data *ahp = x->data;  
  181.  if (!ahp)  
  182.   return;  
  183. // 释放初始化向量空间  
  184.  kfree(ahp->work_icv);  
  185.  ahp->work_icv = NULL;  
  186. // 算法描述释放  
  187.  crypto_free_hash(ahp->tfm);  
  188.  ahp->tfm = NULL;  
  189. // AH数据结构释放  
  190.  kfree(ahp);  
  191. }  
  192.   
  193. 8.1.3.3 协议输入  
  194.   
  195. // 接收数据处理, 在xfrm4_rcv_encap()函数中调用  
  196. // 进行AH认证, 剥离AH头  
  197. static int ah_input(struct xfrm_state *x, struct sk_buff *skb)  
  198. {  
  199.  int ah_hlen;  
  200.  int ihl;  
  201.  int err = -EINVAL;  
  202.  struct iphdr *iph;  
  203.  struct ip_auth_hdr *ah;  
  204.  struct ah_data *ahp;  
  205. // IP头备份空间  
  206.  char work_buf[60];  
  207. // skb数据包要准备留出AH头空间  
  208.  if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr)))  
  209.   goto out;  
  210. // IP上层数据为AH数据  
  211.  ah = (struct ip_auth_hdr*)skb->data;  
  212. // SA相关的AH处理数据  
  213.  ahp = x->data;  
  214.  ah_hlen = (ah->hdrlen + 2) << 2;  
  215. // AH头部长度合法性检查  
  216.  if (ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_full_len) &&  
  217.      ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len))  
  218.   goto out;  
  219. // skb数据包要准备留出实际AH头空间  
  220.  if (!pskb_may_pull(skb, ah_hlen))  
  221.   goto out;  
  222.  /* We are going to _remove_ AH header to keep sockets happy, 
  223.   * so... Later this can change. */  
  224. // 对于clone的包要复制成独立包  
  225.  if (skb_cloned(skb) &&  
  226.      pskb_expand_head(skb, 00, GFP_ATOMIC))  
  227.   goto out;  
  228.  skb->ip_summed = CHECKSUM_NONE;  
  229. // 可能包已经进行了复制, 所以对ah重新赋值  
  230.  ah = (struct ip_auth_hdr*)skb->data;  
  231.  iph = skb->nh.iph;  
  232. // IP头长度  
  233.  ihl = skb->data - skb->nh.raw;  
  234. // 备份外部IP头数据  
  235.  memcpy(work_buf, iph, ihl);  
  236. // 将IP头中的一些参数清零, 这些参数不进行认证  
  237.  iph->ttl = 0;  
  238.  iph->tos = 0;  
  239.  iph->frag_off = 0;  
  240.  iph->check = 0;  
  241. // IP头长度超过20字节时,处理IP选项参数  
  242.  if (ihl > sizeof(*iph)) {  
  243.   u32 dummy;  
  244.   if (ip_clear_mutable_options(iph, &dummy))  
  245.    goto out;  
  246.  }  
  247.         {  
  248. // 认证数据缓冲区  
  249.   u8 auth_data[MAX_AH_AUTH_LEN];  
  250. // 拷贝数据包中的认证数据到缓冲区  
  251.   memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);  
  252. // 包括IP头部分数据  
  253.   skb_push(skb, ihl);  
  254. // 计算认证值是否匹配, 非0表示出错  
  255.   err = ah_mac_digest(ahp, skb, ah->auth_data);  
  256. // 认证失败返回错误  
  257.   if (err)  
  258.    goto out;  
  259.   err = -EINVAL;  
  260. // 复制一定长度的认证数据作为初始化向量  
  261.   if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) {  
  262.    x->stats.integrity_failed++;  
  263.    goto out;  
  264.   }  
  265.  }  
  266. // 将备份的IP头缓冲区中的协议改为AH内部包裹的协议  
  267.  ((struct iphdr*)work_buf)->protocol = ah->nexthdr;  
  268. // 将原来IP头数据拷贝到原来AH头后面作为新IP头  
  269.  skb->h.raw = memcpy(skb->nh.raw += ah_hlen, work_buf, ihl);  
  270. // skb包缩减原来的IP头和AH头, 以新IP头作为数据开始  
  271.  __skb_pull(skb, ah_hlen + ihl);  
  272.  return 0;  
  273. out:  
  274.  return err;  
  275. }  
  276.   
  277. 8.1.3.4 协议输出  
  278.   
  279. // 发送数据处理, 在xfrm4_output_one()中调用  
  280. // 计算AH认证值, 添加AH头  
  281. static int ah_output(struct xfrm_state *x, struct sk_buff *skb)  
  282. {  
  283.  int err;  
  284.  struct iphdr *iph, *top_iph;  
  285.  struct ip_auth_hdr *ah;  
  286.  struct ah_data *ahp;  
  287. // 临时IP头缓冲区, 最大IP头60字节  
  288.  union {  
  289.   struct iphdr iph;  
  290.   char   buf[60];  
  291.  } tmp_iph;  
  292. // 当前的IP头将作为最外部IP头  
  293.  top_iph = skb->nh.iph;  
  294. // 临时IP头,用于临时保存IP头内部分字段数据  
  295.  iph = &tmp_iph.iph;  
  296. // 将当前IP头中不进行认证的字段数据复制到临时IP头  
  297.  iph->tos = top_iph->tos;  
  298.  iph->ttl = top_iph->ttl;  
  299.  iph->frag_off = top_iph->frag_off;  
  300. // 如果有IP选项, 处理IP选项  
  301.  if (top_iph->ihl != 5) {  
  302.   iph->daddr = top_iph->daddr;  
  303.   memcpy(iph+1, top_iph+1, top_iph->ihl*4 - sizeof(struct iphdr));  
  304.   err = ip_clear_mutable_options(top_iph, &top_iph->daddr);  
  305.   if (err)  
  306.    goto error;  
  307.  }  
  308. // AH头定位在外部IP头后面, skb缓冲中已经预留出AH头的数据部分了,  
  309. // 这是通过mode->output函数预留的, 通常调用type->output前要调用mode->oputput  
  310.  ah = (struct ip_auth_hdr *)((char *)top_iph+top_iph->ihl*4);  
  311. // AH中的下一个头用原来的外部IP头中的协议  
  312.  ah->nexthdr = top_iph->protocol;  
  313. // 将外部IP头的不进行认证计算的部分字段清零  
  314.  top_iph->tos = 0;  
  315.  top_iph->tot_len = htons(skb->len);  
  316.  top_iph->frag_off = 0;  
  317.  top_iph->ttl = 0;  
  318. // IP协议改为AH  
  319.  top_iph->protocol = IPPROTO_AH;  
  320.  top_iph->check = 0;  
  321. // AH数据处理结构  
  322.  ahp = x->data;  
  323. // AH头长度对齐  
  324.  ah->hdrlen  = (XFRM_ALIGN8(sizeof(struct ip_auth_hdr) +  
  325.        ahp->icv_trunc_len) >> 2) - 2;  
  326. // AH头参数赋值  
  327.  ah->reserved = 0;  
  328. // SPI值  
  329.  ah->spi = x->id.spi;  
  330. // 序列号  
  331.  ah->seq_no = htonl(++x->replay.oseq);  
  332. // 通知防止重放攻击处理, 更新序列号  
  333.  xfrm_aevent_doreplay(x);  
  334. // 对skb进行AH认证值的计算  
  335.  err = ah_mac_digest(ahp, skb, ah->auth_data);  
  336.  if (err)  
  337.   goto error;  
  338. // 赋值初始化向量值到认证数据部分  
  339.  memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len);  
  340. // 恢复原来IP头的的不认证部分的值  
  341.  top_iph->tos = iph->tos;  
  342.  top_iph->ttl = iph->ttl;  
  343.  top_iph->frag_off = iph->frag_off;  
  344.  if (top_iph->ihl != 5) {  
  345.   top_iph->daddr = iph->daddr;  
  346.   memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr));  
  347.  }  
  348. // 重新计算IP头的认证值  
  349.  ip_send_check(top_iph);  
  350.  err = 0;  
  351. error:  
  352.  return err;  
  353. }  
  354.    
  355. 8.2 ESP  
  356.   
  357. 8.2.1 初始化  
  358.   
  359. /* net/ipv4/esp4.c */  
  360. static int __init esp4_init(void)  
  361. {  
  362. // 登记ESP协议的xfrm协议处理结构  
  363.  if (xfrm_register_type(&esp_type, AF_INET) < 0) {  
  364.   printk(KERN_INFO "ip esp init: can't add xfrm type\n");  
  365.   return -EAGAIN;  
  366.  }  
  367. // 登记ESP协议到IP协议  
  368.  if (inet_add_protocol(&esp4_protocol, IPPROTO_ESP) < 0) {  
  369.   printk(KERN_INFO "ip esp init: can't add protocol\n");  
  370.   xfrm_unregister_type(&esp_type, AF_INET);  
  371.   return -EAGAIN;  
  372.  }  
  373.  return 0;  
  374. }  
  375.   
  376. 8.2.2 IPV4下的ESP协议处理结构  
  377.   
  378. // ESP协议处理结构, 接收到IPV4包后, 系统根据IP头中的protocol  
  379. // 字段选择相应的上层协议处理函数, 当IP协议号是50时, 数据包将  
  380. // 调用该结构的handler处理函数:  
  381. static struct net_protocol esp4_protocol = {  
  382.  .handler = xfrm4_rcv,  
  383.  .err_handler = esp4_err,  
  384.  .no_policy = 1,  
  385. };  
  386.   
  387. ESP协议结构的handler函数也是xfrm4_rcv, 在net/ipv4/xfrm4_input.c 中定义,  
  388. 在上一篇中进行了介绍.  
  389.   
  390. // 错误处理, 收到ICMP错误包时的处理情况, 此时的skb包是ICMP包  
  391. static void esp4_err(struct sk_buff *skb, u32 info)  
  392. {  
  393. // 应用层, data指向ICMP错误包里的内部IP头  
  394.  struct iphdr *iph = (struct iphdr*)skb->data;  
  395. // ESP头  
  396.  struct ip_esp_hdr *esph = (struct ip_esp_hdr*)(skb->data+(iph->ihl<<2));  
  397.  struct xfrm_state *x;  
  398. // ICMP错误类型检查, 本处理函数只处理"目的不可达"和"需要分片"两种错误  
  399.  if (skb->h.icmph->type != ICMP_DEST_UNREACH ||  
  400.      skb->h.icmph->code != ICMP_FRAG_NEEDED)  
  401.   return;  
  402. // 重新查找SA  
  403.  x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET);  
  404.  if (!x)  
  405.   return;  
  406.  NETDEBUG(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%08x\n",  
  407.    ntohl(esph->spi), ntohl(iph->daddr));  
  408.  xfrm_state_put(x);  
  409. }  
  410.   
  411. 8.2.3 ESP4协议的IPSEC处理结构  
  412.   
  413. static struct xfrm_type esp_type =  
  414. {  
  415.  .description = "ESP4",  
  416.  .owner  = THIS_MODULE,  
  417.  .proto       = IPPROTO_ESP,  
  418. // 状态初始化  
  419.  .init_state = esp_init_state,  
  420. // 协议释放  
  421.  .destructor = esp_destroy,  
  422. // 计算最大长度  
  423.  .get_max_size = esp4_get_max_size,  
  424. // 协议输入  
  425.  .input  = esp_input,  
  426. // 协议输出  
  427.  .output  = esp_output  
  428. };  
  429.   
  430. 8.2.3.1 状态初始化  
  431. esp_data数据结构:  
  432. /* include/net/esp.h */  
  433. struct esp_data  
  434. {  
  435.  struct scatterlist  sgbuf[ESP_NUM_FAST_SG];  
  436.  /* Confidentiality */  
  437. // 加密使用的相关数据  
  438.  struct {  
  439. // 密钥  
  440.   u8   *key;  /* Key */  
  441. // 密钥长度  
  442.   int   key_len; /* Key length */  
  443. // 填充长度  
  444.   int   padlen;  /* 0..255 */  
  445.   /* ivlen is offset from enc_data, where encrypted data start. 
  446.    * It is logically different of crypto_tfm_alg_ivsize(tfm). 
  447.    * We assume that it is either zero (no ivec), or 
  448.    * >= crypto_tfm_alg_ivsize(tfm). */  
  449. // 初始化向量长度  
  450.   int   ivlen;  
  451. // 初始化向量是否初始化标志  
  452.   int   ivinitted;  
  453. // 初始化向量  
  454.   u8   *ivec;  /* ivec buffer */  
  455. // 加密算法  
  456.   struct crypto_blkcipher *tfm;  /* crypto handle */  
  457.  } conf;  
  458.  /* Integrity. It is active when icv_full_len != 0 */  
  459. // 认证使用的相关数据  
  460.  struct {  
  461. // 密钥  
  462.   u8   *key;  /* Key */  
  463. // 密钥长度  
  464.   int   key_len; /* Length of the key */  
  465. // 初始化向量  
  466.   u8   *work_icv;  
  467. // 初始化向量全长  
  468.   int   icv_full_len;  
  469. // 初始化向量截断长度  
  470.   int   icv_trunc_len;  
  471. // 初始化向量更新函数, 好象没用  
  472.   void   (*icv)(struct esp_data*,  
  473.                                  struct sk_buff *skb,  
  474.                                  int offset, int len, u8 *icv);  
  475. // HASH算法  
  476.   struct crypto_hash *tfm;  
  477.  } auth;  
  478. };  
  479. // ESP的esp_data数据结构初始化  
  480. static int esp_init_state(struct xfrm_state *x)  
  481. {  
  482.  struct esp_data *esp = NULL;  
  483.  struct crypto_blkcipher *tfm;  
  484.  /* null auth and encryption can have zero length keys */  
  485. // 如果有认证算法, 密钥至少512, ESP的认证处理是可选的, 但在实际中都会使用认证  
  486.  if (x->aalg) {  
  487.   if (x->aalg->alg_key_len > 512)  
  488.    goto error;  
  489.  }  
  490. // ESP加密算法是必须的  
  491.  if (x->ealg == NULL)  
  492.   goto error;  
  493. // 分配esp_data数据结构空间  
  494.  esp = kzalloc(sizeof(*esp), GFP_KERNEL);  
  495.  if (esp == NULL)  
  496.   return -ENOMEM;  
  497. // 如果定义了认证算法, 初始化认证算法参数, 和AH类似  
  498.  if (x->aalg) {  
  499.   struct xfrm_algo_desc *aalg_desc;  
  500.   struct crypto_hash *hash;  
  501. // 认证密钥和长度设置  
  502.   esp->auth.key = x->aalg->alg_key;  
  503.   esp->auth.key_len = (x->aalg->alg_key_len+7)/8;  
  504. // 分配HASH算法的实现  
  505.   hash = crypto_alloc_hash(x->aalg->alg_name, 0,  
  506.       CRYPTO_ALG_ASYNC);  
  507.   if (IS_ERR(hash))  
  508.    goto error;  
  509.   esp->auth.tfm = hash;  
  510. // 设置HASH算法密钥  
  511.   if (crypto_hash_setkey(hash, esp->auth.key, esp->auth.key_len))  
  512.    goto error;  
  513. // 找到算法描述  
  514.   aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);  
  515.   BUG_ON(!aalg_desc);  
  516. // 检查算法初始化向量长度合法性  
  517.   if (aalg_desc->uinfo.auth.icv_fullbits/8 !=  
  518.       crypto_hash_digestsize(hash)) {  
  519.    NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n",  
  520.      x->aalg->alg_name,  
  521.      crypto_hash_digestsize(hash),  
  522.      aalg_desc->uinfo.auth.icv_fullbits/8);  
  523.    goto error;  
  524.   }  
  525. // 初始化向量的全长和截断长度  
  526.   esp->auth.icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8;  
  527.   esp->auth.icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8;  
  528. // 分配全长度的初始化向量空间  
  529.   esp->auth.work_icv = kmalloc(esp->auth.icv_full_len, GFP_KERNEL);  
  530.   if (!esp->auth.work_icv)  
  531.    goto error;  
  532.  }  
  533. // 初始化加密算法相关参数, ESP使用的加密算法都是对称块加密算法, 不可能用非对称算法的  
  534. // 加密密钥  
  535.  esp->conf.key = x->ealg->alg_key;  
  536. // 加密密钥长度  
  537.  esp->conf.key_len = (x->ealg->alg_key_len+7)/8;  
  538. // 分配加密算法的具体实现结构  
  539.  tfm = crypto_alloc_blkcipher(x->ealg->alg_name, 0, CRYPTO_ALG_ASYNC);  
  540.  if (IS_ERR(tfm))  
  541.   goto error;  
  542.  esp->conf.tfm = tfm;  
  543. // 初始化向量大小  
  544.  esp->conf.ivlen = crypto_blkcipher_ivsize(tfm);  
  545. // 填充数据长度初始化为0  
  546.  esp->conf.padlen = 0;  
  547. // 初始化向量长度非0, 分配具体的初始化向量空间  
  548.  if (esp->conf.ivlen) {  
  549.   esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL);  
  550.   if (unlikely(esp->conf.ivec == NULL))  
  551.    goto error;  
  552.   esp->conf.ivinitted = 0;  
  553.  }  
  554. // 设置加密算法密钥  
  555.  if (crypto_blkcipher_setkey(tfm, esp->conf.key, esp->conf.key_len))  
  556.   goto error;  
  557. // 定义SA中ESP头部长度: ESP头加初始化向量长度  
  558. // 反映在ESP封装操作时要将数据包增加的长度  
  559.  x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen;  
  560. // 如果是通道模式, 还需要增加IP头长度  
  561.  if (x->props.mode == XFRM_MODE_TUNNEL)  
  562.   x->props.header_len += sizeof(struct iphdr);  
  563. // 如果要进行UDP封装  
  564.  if (x->encap) {  
  565.   struct xfrm_encap_tmpl *encap = x->encap;  
  566.   switch (encap->encap_type) {  
  567.   default:  
  568.    goto error;  
  569.   case UDP_ENCAP_ESPINUDP:  
  570. // 该类型封装增加UDP头长度  
  571.    x->props.header_len += sizeof(struct udphdr);  
  572.    break;  
  573.   case UDP_ENCAP_ESPINUDP_NON_IKE:  
  574. // 该类型封装增加UDP头长度外加加8字节  
  575.    x->props.header_len += sizeof(struct udphdr) + 2 * sizeof(u32);  
  576.    break;  
  577.   }  
  578.  }  
  579. // 将esp_data作为SA的data指针  
  580.  x->data = esp;  
  581. // 追踪长度, 最大增加长度和当前的计算的增加长度的差值,在路由时会用到  
  582. // 对于AH, 由于没有定义get_max_size(), 该值位0  
  583.  x->props.trailer_len = esp4_get_max_size(x, 0) - x->props.header_len;  
  584.  return 0;  
  585. error:  
  586.  x->data = esp;  
  587.  esp_destroy(x);  
  588.  x->data = NULL;  
  589.  return -EINVAL;  
  590. }  
  591.   
  592. 8.2.3.2 协议释放  
  593.   
  594. // 该函数被xfrm状态(SA)释放函数xfrm_state_gc_destroy()调用  
  595. static void esp_destroy(struct xfrm_state *x)  
  596. {  
  597.  struct esp_data *esp = x->data;  
  598.  if (!esp)  
  599.   return;  
  600. // 释放加密算法  
  601.  crypto_free_blkcipher(esp->conf.tfm);  
  602.  esp->conf.tfm = NULL;  
  603. // 释放加密初始化向量  
  604.  kfree(esp->conf.ivec);  
  605.  esp->conf.ivec = NULL;  
  606. // 释放认证算法  
  607.  crypto_free_hash(esp->auth.tfm);  
  608.  esp->auth.tfm = NULL;  
  609. // 释放认证初始化向量  
  610.  kfree(esp->auth.work_icv);  
  611.  esp->auth.work_icv = NULL;  
  612. // 释放esp_data  
  613.  kfree(esp);  
  614. }  
  615.   
  616. 8.2.3.3 计算最大长度  
  617.   
  618. // 在xfrm_state_mtu()函数中调用, 计算最大增加的数据长度  
  619. // AH中没有该函数, 增加的长度使用x->props.header_len  
  620. static u32 esp4_get_max_size(struct xfrm_state *x, int mtu)  
  621. {  
  622.  struct esp_data *esp = x->data;  
  623. // 加密块长度, 按4字节对齐  
  624.  u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4);  
  625.  int enclen = 0;  
  626.  switch (x->props.mode) {  
  627.  case XFRM_MODE_TUNNEL:  
  628. // 通道模式下的MTU, 按加密块大小对齐, +2是要包括2字节数据长度  
  629.   mtu = ALIGN(mtu +2, blksize);  
  630.   break;  
  631.  default:  
  632.  case XFRM_MODE_TRANSPORT:  
  633.   /* The worst case */  
  634. // 传输模式下, MTU先按4字节对齐, 再加块长度减4  
  635.   mtu = ALIGN(mtu + 24) + blksize - 4;  
  636.   break;  
  637.  case XFRM_MODE_BEET:  
  638.    /* The worst case. */  
  639.   enclen = IPV4_BEET_PHMAXLEN;  
  640.   mtu = ALIGN(mtu + enclen + 2, blksize);  
  641.   break;  
  642.  }  
  643. // 如果加密算法中定义了填充长度, MTU也要按填充长度对齐  
  644.  if (esp->conf.padlen)  
  645.   mtu = ALIGN(mtu, esp->conf.padlen);  
  646. // 返回MTU加提议中需要增加的头部长度和认证初始化向量的截断长度  
  647. // enclen只在BEET模式下非0, 在通道和传输模式下都是0  
  648.  return mtu + x->props.header_len + esp->auth.icv_trunc_len - enclen;  
  649. }  
  650.    
  651. 8.2.3.4 协议输入  
  652.   
  653. struct scatterlist结构说明:  
  654. /* include/asm-i386/scatterlist.h */  
  655. struct scatterlist {  
  656.     struct page  *page;  
  657.     unsigned int offset;  
  658.     dma_addr_t  dma_address;  
  659.     unsigned int length;  
  660. };  
  661.   
  662. /* 
  663.  * Note: detecting truncated vs. non-truncated authentication data is very 
  664.  * expensive, so we only support truncated data, which is the recommended 
  665.  * and common case. 
  666.  */  
  667. // 接收数据处理, 在xfrm4_rcv_encap()函数中调用  
  668. // 进行ESP认证解密, 剥离ESP头, 解密成普通数据包, 数据包长度减少  
  669. // 输入的数据包是ESP包  
  670. static int esp_input(struct xfrm_state *x, struct sk_buff *skb)  
  671. {  
  672.  struct iphdr *iph;  
  673.  struct ip_esp_hdr *esph;  
  674.  struct esp_data *esp = x->data;  
  675.  struct crypto_blkcipher *tfm = esp->conf.tfm;  
  676.  struct blkcipher_desc desc = { .tfm = tfm };  
  677.  struct sk_buff *trailer;  
  678.  int blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);  
  679. // 认证初始化向量截断长度  
  680.  int alen = esp->auth.icv_trunc_len;  
  681. // 需要加密的数据长度: 总长减ESP头, 加密初始化向量长度, 认证初始化向量长度  
  682.  int elen = skb->len - sizeof(struct ip_esp_hdr) - esp->conf.ivlen - alen;  
  683.  int nfrags;  
  684.  int ihl;  
  685.  u8 nexthdr[2];  
  686.  struct scatterlist *sg;  
  687.  int padlen;  
  688.  int err;  
  689. // 在skb头留出ESP头的空间  
  690.  if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr)))  
  691.   goto out;  
  692. // 检查需要加密的数据长度, 必须大于0而且按块大小对齐的  
  693.  if (elen <= 0 || (elen & (blksize-1)))  
  694.   goto out;  
  695.  /* If integrity check is required, do this. */  
  696. // 认证计算处理  
  697.  if (esp->auth.icv_full_len) {  
  698.   u8 sum[alen];  
  699. // 计算认证值, 认证值保存在esp_data结构中  
  700.   err = esp_mac_digest(esp, skb, 0, skb->len - alen);  
  701.   if (err)  
  702.    goto out;  
  703. // 将skb中的认证初始化向量部分数据拷贝到缓冲区sum中  
  704.   if (skb_copy_bits(skb, skb->len - alen, sum, alen))  
  705.    BUG();  
  706. // 比较sum中的向量值和认证算法结构中的向量值是否匹配, 数据包正常情况下应该是相同的  
  707.   if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {  
  708.    x->stats.integrity_failed++;  
  709.    goto out;  
  710.   }  
  711.  }  
  712. // 使数据包是可写的  
  713.  if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0)  
  714.   goto out;  
  715.  skb->ip_summed = CHECKSUM_NONE;  
  716. // 定位在数据包中的ESP头位置, 为当前的data位置  
  717.  esph = (struct ip_esp_hdr*)skb->data;  
  718.  /* Get ivec. This can be wrong, check against another impls. */  
  719. // 设置加密算法的初始化向量  
  720.  if (esp->conf.ivlen)  
  721.   crypto_blkcipher_set_iv(tfm, esph->enc_data, esp->conf.ivlen);  
  722.  sg = &esp->sgbuf[0];  
  723.  if (unlikely(nfrags > ESP_NUM_FAST_SG)) {  
  724.   sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);  
  725.   if (!sg)  
  726.    goto out;  
  727.  }  
  728.  skb_to_sgvec(skb, sg, sizeof(struct ip_esp_hdr) + esp->conf.ivlen, elen);  
  729. // 解密操作, 返回非0表示失败  
  730.  err = crypto_blkcipher_decrypt(&desc, sg, sg, elen);  
  731.  if (unlikely(sg != &esp->sgbuf[0]))  
  732.   kfree(sg);  
  733. // 解密失败返回  
  734.  if (unlikely(err))  
  735.   return err;  
  736. // 拷贝两字节数据  
  737.  if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2))  
  738.   BUG();  
  739.  padlen = nexthdr[0];  
  740.  if (padlen+2 >= elen)  
  741.   goto out;  
  742.  /* ... check padding bits here. Silly. :-) */  
  743. // 新的IP头  
  744.  iph = skb->nh.iph;  
  745.  ihl = iph->ihl * 4;  
  746. // 如果是NAT穿越情况, 进行一些处理  
  747.  if (x->encap) {  
  748. // xfrm封装模板  
  749.   struct xfrm_encap_tmpl *encap = x->encap;  
  750. // 定位UDP数据头位置, 在IP头之后  
  751.   struct udphdr *uh = (void *)(skb->nh.raw + ihl);  
  752.   /* 
  753.    * 1) if the NAT-T peer's IP or port changed then 
  754.    *    advertize the change to the keying daemon. 
  755.    *    This is an inbound SA, so just compare 
  756.    *    SRC ports. 
  757.    */  
  758. // 如果IP头源地址和SA提议中的源地址不同或源端口不同  
  759.   if (iph->saddr != x->props.saddr.a4 ||  
  760.       uh->source != encap->encap_sport) {  
  761.    xfrm_address_t ipaddr;  
  762. // 保存当前IP头源地址  
  763.    ipaddr.a4 = iph->saddr;  
  764. // 进行NAT通知回调处理  
  765.    km_new_mapping(x, &ipaddr, uh->source);  
  766.       
  767.    /* XXX: perhaps add an extra 
  768.     * policy check here, to see 
  769.     * if we should allow or 
  770.     * reject a packet from a 
  771.     * different source 
  772.     * address/port. 
  773.     */  
  774.   }  
  775.    
  776.   /* 
  777.    * 2) ignore UDP/TCP checksums in case 
  778.    *    of NAT-T in Transport Mode, or 
  779.    *    perform other post-processing fixes 
  780.    *    as per draft-ietf-ipsec-udp-encaps-06, 
  781.    *    section 3.1.2 
  782.    */  
  783. // 如果是传输模式或BEET模式, 设置不需要计算校验和  
  784.   if (x->props.mode == XFRM_MODE_TRANSPORT ||  
  785.       x->props.mode == XFRM_MODE_BEET)  
  786.    skb->ip_summed = CHECKSUM_UNNECESSARY;  
  787.  }  
  788. // 新IP头中协议  
  789.  iph->protocol = nexthdr[1];  
  790. // 缩减skb数据包长度  
  791.  pskb_trim(skb, skb->len - alen - padlen - 2);  
  792. // 重新定位IP上层数据头位置  
  793.  skb->h.raw = __skb_pull(skb, sizeof(*esph) + esp->conf.ivlen) - ihl;  
  794.  return 0;  
  795. out:  
  796.  return -EINVAL;  
  797. }  
  798.   
  799. 8.2.3.4 协议输出  
  800.   
  801. // 发送数据处理, 在xfrm4_output_one()中调用  
  802. // 添加ESP头, 对数据包进行加密和认证处理, 数据包长度扩大  
  803. // 在NAT穿越情况下会封装为UDP数据  
  804. static int esp_output(struct xfrm_state *x, struct sk_buff *skb)  
  805. {  
  806.  int err;  
  807.  struct iphdr *top_iph;  
  808.  struct ip_esp_hdr *esph;  
  809.  struct crypto_blkcipher *tfm;  
  810.  struct blkcipher_desc desc;  
  811.  struct esp_data *esp;  
  812.  struct sk_buff *trailer;  
  813.  int blksize;  
  814.  int clen;  
  815.  int alen;  
  816.  int nfrags;  
  817.  /* Strip IP+ESP header. */  
  818. // 缩减skb数据, 减去IP头和ESP头, 剩下的数据就是要进行加密和认证的部分  
  819.  __skb_pull(skb, skb->h.raw - skb->data);  
  820.  /* Now skb is pure payload to encrypt */  
  821.  err = -ENOMEM;  
  822.  /* Round to block size */  
  823. // 加密块的初始值  
  824.  clen = skb->len;  
  825. // 获取SA的esp_data数据结构  
  826.  esp = x->data;  
  827. // 认证初始化向量截断长度  
  828.  alen = esp->auth.icv_trunc_len;  
  829. // 加密算法  
  830.  tfm = esp->conf.tfm;  
  831. // 给块加密算法描述结构赋值  
  832.  desc.tfm = tfm;  
  833.  desc.flags = 0;  
  834. // 每个加密块大小  
  835.  blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);  
  836. // 对齐要加密的数据总长  
  837.  clen = ALIGN(clen + 2, blksize);  
  838. // 如果要考虑填充, 继续对齐  
  839.  if (esp->conf.padlen)  
  840.   clen = ALIGN(clen, esp->conf.padlen);  
  841. // 使数据包可写  
  842.  if ((nfrags = skb_cow_data(skb, clen-skb->len+alen, &trailer)) < 0)  
  843.   goto error;  
  844.  /* Fill padding... */  
  845. // 长度对齐后填充多余长度部分内容  
  846.  do {  
  847.   int i;  
  848.   for (i=0; i<clen-skb->len - 2; i++)  
  849.    *(u8*)(trailer->tail + i) = i+1;  
  850.  } while (0);  
  851. // 最后两字节表示填充数据的长度  
  852.  *(u8*)(trailer->tail + clen-skb->len - 2) = (clen - skb->len)-2;  
  853.  pskb_put(skb, trailer, clen - skb->len);  
  854. // 在将IP头部分扩展回来  
  855.  __skb_push(skb, skb->data - skb->nh.raw);  
  856. // 现在的IP头作为外部IP头  
  857.  top_iph = skb->nh.iph;  
  858. // esp头跟在IP头后  
  859.  esph = (struct ip_esp_hdr *)(skb->nh.raw + top_iph->ihl*4);  
  860. // 数据总长增加认证部分长度  
  861.  top_iph->tot_len = htons(skb->len + alen);  
  862.  *(u8*)(trailer->tail - 1) = top_iph->protocol;  
  863.  /* this is non-NULL only with UDP Encapsulation */  
  864.  if (x->encap) {  
  865. // NAT穿越情况下要将数据封装为UDP包  
  866.   struct xfrm_encap_tmpl *encap = x->encap;  
  867.   struct udphdr *uh;  
  868.   u32 *udpdata32;  
  869. // IP头后改为UDP头  
  870.   uh = (struct udphdr *)esph;  
  871. // 填充UDP头参数, 源端口, 目的端口, UDP数据长度  
  872.   uh->source = encap->encap_sport;  
  873.   uh->dest = encap->encap_dport;  
  874.   uh->len = htons(skb->len + alen - top_iph->ihl*4);  
  875. // 校验和为0, 表示不需要计算校验和, ESP本身就进行认证了  
  876.   uh->check = 0;  
  877.   switch (encap->encap_type) {  
  878.   default:  
  879.   case UDP_ENCAP_ESPINUDP:  
  880. // 在该模式下ESP头跟在UDP头后面  
  881.    esph = (struct ip_esp_hdr *)(uh + 1);  
  882.    break;  
  883.   case UDP_ENCAP_ESPINUDP_NON_IKE:  
  884. // 在该模式下ESP头跟在UDP头后面8字节处  
  885.    udpdata32 = (u32 *)(uh + 1);  
  886.    udpdata32[0] = udpdata32[1] = 0;  
  887.    esph = (struct ip_esp_hdr *)(udpdata32 + 2);  
  888.    break;  
  889.   }  
  890. // 外部IP头协议是UDP  
  891.   top_iph->protocol = IPPROTO_UDP;  
  892.  } else  
  893. // 非NAT穿越情况下, 外部IP头中的协议是ESP  
  894.   top_iph->protocol = IPPROTO_ESP;  
  895. // 填充ESP头中的SPI和序列号  
  896.  esph->spi = x->id.spi;  
  897.  esph->seq_no = htonl(++x->replay.oseq);  
  898. // 序列号更新通知回调  
  899.  xfrm_aevent_doreplay(x);  
  900. // 如果加密初始化向量长度非零, 设置加密算法中的初始化向量  
  901.  if (esp->conf.ivlen) {  
  902.   if (unlikely(!esp->conf.ivinitted)) {  
  903.    get_random_bytes(esp->conf.ivec, esp->conf.ivlen);  
  904.    esp->conf.ivinitted = 1;  
  905.   }  
  906.   crypto_blkcipher_set_iv(tfm, esp->conf.ivec, esp->conf.ivlen);  
  907.  }  
  908. // 加密操作  
  909.  do {  
  910.   struct scatterlist *sg = &esp->sgbuf[0];  
  911.   if (unlikely(nfrags > ESP_NUM_FAST_SG)) {  
  912.    sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);  
  913.    if (!sg)  
  914.     goto error;  
  915.   }  
  916.   skb_to_sgvec(skb, sg, esph->enc_data+esp->conf.ivlen-skb->data, clen);  
  917. // 对数据加密  
  918.   err = crypto_blkcipher_encrypt(&desc, sg, sg, clen);  
  919.   if (unlikely(sg != &esp->sgbuf[0]))  
  920.    kfree(sg);  
  921.  } while (0);  
  922.  if (unlikely(err))  
  923.   goto error;  
  924. // 将加密算法初始化向量拷贝到数据包  
  925.  if (esp->conf.ivlen) {  
  926.   memcpy(esph->enc_data, esp->conf.ivec, esp->conf.ivlen);  
  927.   crypto_blkcipher_get_iv(tfm, esp->conf.ivec, esp->conf.ivlen);  
  928.  }  
  929. // 认证计算, 计算出HASH值并拷贝到数据包中  
  930.  if (esp->auth.icv_full_len) {  
  931.   err = esp_mac_digest(esp, skb, (u8 *)esph - skb->data,  
  932.          sizeof(*esph) + esp->conf.ivlen + clen);  
  933.   memcpy(pskb_put(skb, trailer, alen), esp->auth.work_icv, alen);  
  934.  }  
  935. // 重新计算外部IP头校验和  
  936.  ip_send_check(top_iph);  
  937. error:  
  938.  return err;  
  939. }  
  940.    
  941. ...... 待续 ......  
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值