]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/esp_output.c
   1 /*      $FreeBSD: src/sys/netinet6/esp_output.c,v 1.1.2.2 2001/07/03 11:01:50 ume Exp $ */ 
   2 /*      $KAME: esp_output.c,v 1.43 2001/03/01 07:10:45 itojun Exp $     */ 
   5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 
   8  * Redistribution and use in source and binary forms, with or without 
   9  * modification, are permitted provided that the following conditions 
  11  * 1. Redistributions of source code must retain the above copyright 
  12  *    notice, this list of conditions and the following disclaimer. 
  13  * 2. Redistributions in binary form must reproduce the above copyright 
  14  *    notice, this list of conditions and the following disclaimer in the 
  15  *    documentation and/or other materials provided with the distribution. 
  16  * 3. Neither the name of the project nor the names of its contributors 
  17  *    may be used to endorse or promote products derived from this software 
  18  *    without specific prior written permission. 
  20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 
  21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 
  24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
  25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
  26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
  27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
  28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
  29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
  36  * RFC1827/2406 Encapsulated Security Payload. 
  39 #include <sys/param.h> 
  40 #include <sys/systm.h> 
  41 #include <sys/malloc.h> 
  43 #include <sys/domain.h> 
  44 #include <sys/protosw.h> 
  45 #include <sys/socket.h> 
  46 #include <sys/socketvar.h> 
  47 #include <sys/errno.h> 
  49 #include <sys/kernel.h> 
  50 #include <sys/syslog.h> 
  53 #include <net/route.h> 
  55 #include <netinet/in.h> 
  56 #include <netinet/in_systm.h> 
  57 #include <netinet/ip.h> 
  58 #include <netinet/in_var.h> 
  61 #include <netinet/ip6.h> 
  62 #include <netinet6/ip6_var.h> 
  63 #include <netinet/icmp6.h> 
  66 #include <netinet6/ipsec.h> 
  68 #include <netinet6/ipsec6.h> 
  70 #include <netinet6/ah.h> 
  72 #include <netinet6/ah6.h> 
  74 #include <netinet6/esp.h> 
  76 #include <netinet6/esp6.h> 
  78 #include <netkey/key.h> 
  79 #include <netkey/keydb.h> 
  81 #include <net/net_osdep.h> 
  83 static int esp_output 
__P((struct mbuf 
*, u_char 
*, struct mbuf 
*, 
  84         struct ipsecrequest 
*, int)); 
  87  * compute ESP header size. 
  91         struct ipsecrequest 
*isr
; 
  94         const struct esp_algorithm 
*algo
; 
  95         const struct ah_algorithm 
*aalgo
; 
 102                 panic("esp_hdrsiz: NULL was passed.\n"); 
 106         if (isr
->saidx
.proto 
!= IPPROTO_ESP
) 
 107                 panic("unsupported mode passed to esp_hdrsiz"); 
 111         if (sav
->state 
!= SADB_SASTATE_MATURE
 
 112          && sav
->state 
!= SADB_SASTATE_DYING
) 
 115         /* we need transport mode ESP. */ 
 116         algo 
= esp_algorithm_lookup(sav
->alg_enc
); 
 125          * right now we don't calcurate the padding size.  simply 
 126          * treat the padding size as constant, for simplicity. 
 128          * XXX variable size padding support 
 130         if (sav
->flags 
& SADB_X_EXT_OLD
) { 
 132                 hdrsiz 
= sizeof(struct esp
) + ivlen 
+ 9; 
 135                 aalgo 
= ah_algorithm_lookup(sav
->alg_auth
); 
 136                 if (aalgo 
&& sav
->replay 
&& sav
->key_auth
) 
 137                         authlen 
= (aalgo
->sumsiz
)(sav
); 
 140                 hdrsiz 
= sizeof(struct newesp
) + ivlen 
+ 9 + authlen
; 
 148          *      sizeof(struct newesp) > sizeof(struct esp). 
 149          *      esp_max_ivlen() = max ivlen for CBC mode 
 150          *      9 = (maximum padding length without random padding length) 
 151          *         + (Pad Length field) + (Next Header field). 
 152          *      16 = maximum ICV we support. 
 154         return sizeof(struct newesp
) + esp_max_ivlen() + 9 + 16; 
 158  * Modify the packet so that the payload is encrypted. 
 159  * The mbuf (m) must start with IPv4 or IPv6 header. 
 160  * On failure, free the given mbuf and return NULL. 
 165  *      IP ......... payload 
 166  * during the encryption: 
 167  *      m   nexthdrp mprev md 
 169  *      IP ............... esp iv payload pad padlen nxthdr 
 170  *                         <--><-><------><---------------> 
 171  *                         esplen plen    extendsiz 
 175  *      <-----------------> espoff 
 178 esp_output(m
, nexthdrp
, md
, isr
, af
) 
 182         struct ipsecrequest 
*isr
; 
 188         struct esptail 
*esptail
; 
 189         struct secasvar 
*sav 
= isr
->sav
; 
 190         const struct esp_algorithm 
*algo
; 
 193         size_t plen
;    /*payload length to be encrypted*/ 
 199         struct ipsecstat 
*stat
; 
 215                 ipseclog((LOG_ERR
, "esp_output: unsupported af %d\n", af
)); 
 216                 return 0;       /* no change at all */ 
 219         /* some sanity check */ 
 220         if ((sav
->flags 
& SADB_X_EXT_OLD
) == 0 && !sav
->replay
) { 
 227                         ip 
= mtod(m
, struct ip 
*); 
 228                         ipseclog((LOG_DEBUG
, "esp4_output: internal error: " 
 229                                 "sav->replay is null: %x->%x, SPI=%u\n", 
 230                                 (u_int32_t
)ntohl(ip
->ip_src
.s_addr
), 
 231                                 (u_int32_t
)ntohl(ip
->ip_dst
.s_addr
), 
 232                                 (u_int32_t
)ntohl(sav
->spi
))); 
 233                         ipsecstat
.out_inval
++; 
 239                         ipseclog((LOG_DEBUG
, "esp6_output: internal error: " 
 240                                 "sav->replay is null: SPI=%u\n", 
 241                                 (u_int32_t
)ntohl(sav
->spi
))); 
 242                         ipsec6stat
.out_inval
++; 
 246                         panic("esp_output: should not reach here"); 
 252         algo 
= esp_algorithm_lookup(sav
->alg_enc
); 
 254                 ipseclog((LOG_ERR
, "esp_output: unsupported algorithm: " 
 255                     "SPI=%u\n", (u_int32_t
)ntohl(sav
->spi
))); 
 263                 panic("invalid ivlen"); 
 269          * XXX inserts ESP header right after IPv4 header.  should 
 270          * chase the header chain. 
 271          * XXX sequential number 
 274         struct ip 
*ip 
= NULL
; 
 277         struct ip6_hdr 
*ip6 
= NULL
; 
 279         size_t esplen
;  /*sizeof(struct esp/newesp)*/ 
 280         size_t esphlen
; /*sizeof(struct esp/newesp) + ivlen*/ 
 281         size_t hlen 
= 0;        /*ip header len*/ 
 283         if (sav
->flags 
& SADB_X_EXT_OLD
) { 
 285                 esplen 
= sizeof(struct esp
); 
 288                 if (sav
->flags 
& SADB_X_EXT_DERIV
) 
 289                         esplen 
= sizeof(struct esp
); 
 291                         esplen 
= sizeof(struct newesp
); 
 293         esphlen 
= esplen 
+ ivlen
; 
 295         for (mprev 
= m
; mprev 
&& mprev
->m_next 
!= md
; mprev 
= mprev
->m_next
) 
 297         if (mprev 
== NULL 
|| mprev
->m_next 
!= md
) { 
 298                 ipseclog((LOG_DEBUG
, "esp%d_output: md is not in chain\n", 
 305         for (n 
= md
; n
; n 
= n
->m_next
) 
 311                 ip 
= mtod(m
, struct ip 
*); 
 313                 hlen 
= IP_VHL_HL(ip
->ip_vhl
) << 2; 
 315                 hlen 
= ip
->ip_hl 
<< 2; 
 321                 ip6 
= mtod(m
, struct ip6_hdr 
*); 
 327         /* make the packet over-writable */ 
 328         mprev
->m_next 
= NULL
; 
 329         if ((md 
= ipsec_copypkt(md
)) == NULL
) { 
 336         espoff 
= m
->m_pkthdr
.len 
- plen
; 
 339          * grow the mbuf to accomodate ESP header. 
 340          * before: IP ... payload 
 341          * after:  IP ... ESP IV payload 
 343         if (M_LEADINGSPACE(md
) < esphlen 
|| (md
->m_flags 
& M_EXT
) != 0) { 
 344                 MGET(n
, M_DONTWAIT
, MT_DATA
); 
 353                 m
->m_pkthdr
.len 
+= esphlen
; 
 354                 esp 
= mtod(n
, struct esp 
*); 
 356                 md
->m_len 
+= esphlen
; 
 357                 md
->m_data 
-= esphlen
; 
 358                 m
->m_pkthdr
.len 
+= esphlen
; 
 359                 esp 
= mtod(md
, struct esp 
*); 
 363         *nexthdrp 
= IPPROTO_ESP
; 
 367                 if (esphlen 
< (IP_MAXPACKET 
- ntohs(ip
->ip_len
))) 
 368                         ip
->ip_len 
= htons(ntohs(ip
->ip_len
) + esphlen
); 
 371                             "IPv4 ESP output: size exceeds limit\n")); 
 372                         ipsecstat
.out_inval
++; 
 381                 /* total packet length will be computed in ip6_output() */ 
 387         /* initialize esp header. */ 
 389         if ((sav
->flags 
& SADB_X_EXT_OLD
) == 0) { 
 391                 nesp 
= (struct newesp 
*)esp
; 
 392                 if (sav
->replay
->count 
== ~0) { 
 393                         if ((sav
->flags 
& SADB_X_EXT_CYCSEQ
) == 0) { 
 394                                 /* XXX Is it noisy ? */ 
 395                                 ipseclog((LOG_WARNING
, 
 396                                     "replay counter overflowed. %s\n", 
 397                                     ipsec_logsastr(sav
))); 
 403                 sav
->replay
->count
++; 
 405                  * XXX sequence number must not be cycled, if the SA is 
 406                  * installed by IKE daemon. 
 408                 nesp
->esp_seq 
= htonl(sav
->replay
->count
); 
 413          * find the last mbuf. make some room for ESP trailer. 
 416         struct ip 
*ip 
= NULL
; 
 424                 padbound 
= algo
->padbound
; 
 427         /* ESP packet, including nxthdr field, must be length of 4n */ 
 431         extendsiz 
= padbound 
- (plen 
% padbound
); 
 433                 extendsiz 
= padbound 
+ 1; 
 439                 randpadmax 
= ip4_esp_randpad
; 
 444                 randpadmax 
= ip6_esp_randpad
; 
 451         if (randpadmax 
< 0 || plen 
+ extendsiz 
>= randpadmax
) 
 457                 randpadmax 
= (randpadmax 
/ padbound
) * padbound
; 
 458                 n 
= (randpadmax 
- plen 
+ extendsiz
) / padbound
; 
 461                         n 
= (random() % n
) * padbound
; 
 466                  * make sure we do not pad too much. 
 467                  * MLEN limitation comes from the trailer attachment 
 469                  * 256 limitation comes from sequential padding. 
 470                  * also, the 1-octet length field in ESP trailer imposes 
 471                  * limitation (but is less strict than sequential padding 
 472                  * as length field do not count the last 2 octets). 
 474                 if (extendsiz 
+ n 
<= MLEN 
&& extendsiz 
+ n 
< 256) 
 479         if (extendsiz 
> MLEN 
|| extendsiz 
>= 256) 
 480                 panic("extendsiz too big in esp_output"); 
 488          * if M_EXT, the external mbuf data may be shared among 
 489          * two consequtive TCP packets, and it may be unsafe to use the 
 492         if (!(n
->m_flags 
& M_EXT
) && extendsiz 
< M_TRAILINGSPACE(n
)) { 
 493                 extend 
= mtod(n
, u_char 
*) + n
->m_len
; 
 494                 n
->m_len 
+= extendsiz
; 
 495                 m
->m_pkthdr
.len 
+= extendsiz
; 
 499                 MGET(nn
, M_DONTWAIT
, MT_DATA
); 
 501                         ipseclog((LOG_DEBUG
, "esp%d_output: can't alloc mbuf", 
 507                 extend 
= mtod(nn
, u_char 
*); 
 508                 nn
->m_len 
= extendsiz
; 
 512                 m
->m_pkthdr
.len 
+= extendsiz
; 
 514         switch (sav
->flags 
& SADB_X_EXT_PMASK
) { 
 515         case SADB_X_EXT_PRAND
: 
 516                 key_randomfill(extend
, extendsiz
); 
 518         case SADB_X_EXT_PZERO
: 
 519                 bzero(extend
, extendsiz
); 
 521         case SADB_X_EXT_PSEQ
: 
 522                 for (i 
= 0; i 
< extendsiz
; i
++) 
 523                         extend
[i
] = (i 
+ 1) & 0xff; 
 527         /* initialize esp trailer. */ 
 528         esptail 
= (struct esptail 
*) 
 529                 (mtod(n
, u_int8_t 
*) + n
->m_len 
- sizeof(struct esptail
)); 
 530         esptail
->esp_nxt 
= nxt
; 
 531         esptail
->esp_padlen 
= extendsiz 
- 2; 
 533         /* modify IP header (for ESP header part only) */ 
 537                 ip 
= mtod(m
, struct ip 
*); 
 538                 if (extendsiz 
< (IP_MAXPACKET 
- ntohs(ip
->ip_len
))) 
 539                         ip
->ip_len 
= htons(ntohs(ip
->ip_len
) + extendsiz
); 
 542                             "IPv4 ESP output: size exceeds limit\n")); 
 543                         ipsecstat
.out_inval
++; 
 552                 /* total packet length will be computed in ip6_output() */ 
 559          * pre-compute and cache intermediate key 
 561         error 
= esp_schedule(algo
, sav
); 
 569          * encrypt the packet, based on security association 
 570          * and the algorithm specified. 
 573                 panic("internal error: no encrypt function"); 
 574         if ((*algo
->encrypt
)(m
, espoff
, plen 
+ extendsiz
, sav
, algo
, ivlen
)) { 
 575                 /* m is already freed */ 
 576                 ipseclog((LOG_ERR
, "packet encryption failure\n")); 
 583          * calculate ICV if required. 
 589         if (sav
->key_auth 
== SADB_AALG_NONE
) 
 593         const struct ah_algorithm 
*aalgo
; 
 594         u_char authbuf
[AH_MAXSUMSIZE
]; 
 602         aalgo 
= ah_algorithm_lookup(sav
->alg_auth
); 
 605         siz 
= ((aalgo
->sumsiz
)(sav
) + 3) & ~(4 - 1); 
 606         if (AH_MAXSUMSIZE 
< siz
) 
 607                 panic("assertion failed for AH_MAXSUMSIZE"); 
 609         if (esp_auth(m
, espoff
, m
->m_pkthdr
.len 
- espoff
, sav
, authbuf
)) { 
 610                 ipseclog((LOG_ERR
, "ESP checksum generation failure\n")); 
 621         if (!(n
->m_flags 
& M_EXT
) && siz 
< M_TRAILINGSPACE(n
)) {        /*XXX*/ 
 623                 m
->m_pkthdr
.len 
+= siz
; 
 624                 p 
= mtod(n
, u_char 
*) + n
->m_len 
- siz
; 
 628                 MGET(nn
, M_DONTWAIT
, MT_DATA
); 
 630                         ipseclog((LOG_DEBUG
, "can't alloc mbuf in esp%d_output", 
 640                 m
->m_pkthdr
.len 
+= siz
; 
 641                 p 
= mtod(nn
, u_char 
*); 
 643         bcopy(authbuf
, p
, siz
); 
 645         /* modify IP header (for ESP header part only) */ 
 649                 ip 
= mtod(m
, struct ip 
*); 
 650                 if (siz 
< (IP_MAXPACKET 
- ntohs(ip
->ip_len
))) 
 651                         ip
->ip_len 
= htons(ntohs(ip
->ip_len
) + siz
); 
 654                             "IPv4 ESP output: size exceeds limit\n")); 
 655                         ipsecstat
.out_inval
++; 
 664                 /* total packet length will be computed in ip6_output() */ 
 673                     "NULL mbuf after encryption in esp%d_output", afnumber
)); 
 676         stat
->out_esphist
[sav
->alg_enc
]++; 
 677         key_sa_recordxfer(sav
, m
); 
 684         panic("something bad in esp_output"); 
 692         struct ipsecrequest 
*isr
; 
 695         if (m
->m_len 
< sizeof(struct ip
)) { 
 696                 ipseclog((LOG_DEBUG
, "esp4_output: first mbuf too short\n")); 
 700         ip 
= mtod(m
, struct ip 
*); 
 701         /* XXX assumes that m->m_next points to payload */ 
 702         return esp_output(m
, &ip
->ip_p
, m
->m_next
, isr
, AF_INET
); 
 708 esp6_output(m
, nexthdrp
, md
, isr
) 
 712         struct ipsecrequest 
*isr
; 
 714         if (m
->m_len 
< sizeof(struct ip6_hdr
)) { 
 715                 ipseclog((LOG_DEBUG
, "esp6_output: first mbuf too short\n")); 
 719         return esp_output(m
, nexthdrp
, md
, isr
, AF_INET6
);