]>
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.3 2002/04/28 05:40:26 suz Exp $ */
2 /* $KAME: esp_output.c,v 1.44 2001/07/26 06:53:15 jinmei 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>
59 #include <netinet/udp.h> /* for nat traversal */
62 #include <netinet/ip6.h>
63 #include <netinet6/ip6_var.h>
64 #include <netinet/icmp6.h>
67 #include <netinet6/ipsec.h>
69 #include <netinet6/ipsec6.h>
71 #include <netinet6/ah.h>
73 #include <netinet6/ah6.h>
75 #include <netinet6/esp.h>
77 #include <netinet6/esp6.h>
79 #include <netkey/key.h>
80 #include <netkey/keydb.h>
82 #include <net/net_osdep.h>
84 #include <sys/kdebug.h>
85 #define DBG_LAYER_BEG NETDBG_CODE(DBG_NETIPSEC, 1)
86 #define DBG_LAYER_END NETDBG_CODE(DBG_NETIPSEC, 3)
87 #define DBG_FNC_ESPOUT NETDBG_CODE(DBG_NETIPSEC, (4 << 8))
88 #define DBG_FNC_ENCRYPT NETDBG_CODE(DBG_NETIPSEC, (5 << 8))
90 static int esp_output(struct mbuf
*, u_char
*, struct mbuf
*,
91 struct ipsecrequest
*, int);
93 extern int esp_udp_encap_port
;
94 extern u_int32_t natt_now
;
97 * compute ESP header size.
101 struct ipsecrequest
*isr
;
103 struct secasvar
*sav
;
104 const struct esp_algorithm
*algo
;
105 const struct ah_algorithm
*aalgo
;
113 panic("esp_hdrsiz: NULL was passed.\n");
117 if (isr
->saidx
.proto
!= IPPROTO_ESP
)
118 panic("unsupported mode passed to esp_hdrsiz");
122 if (sav
->state
!= SADB_SASTATE_MATURE
123 && sav
->state
!= SADB_SASTATE_DYING
)
126 /* we need transport mode ESP. */
127 algo
= esp_algorithm_lookup(sav
->alg_enc
);
135 maxpad
= algo
->padbound
;
138 maxpad
+= 1; /* maximum 'extendsiz' is padbound + 1, see esp_output */
140 if (sav
->flags
& SADB_X_EXT_OLD
) {
142 hdrsiz
= sizeof(struct esp
) + ivlen
+ maxpad
;
145 aalgo
= ah_algorithm_lookup(sav
->alg_auth
);
146 if (aalgo
&& sav
->replay
&& sav
->key_auth
)
147 authlen
= (aalgo
->sumsiz
)(sav
);
150 hdrsiz
= sizeof(struct newesp
) + ivlen
+ maxpad
+ authlen
;
154 * If the security association indicates that NATT is required,
155 * add the size of the NATT encapsulation header:
157 if ((sav
->flags
& SADB_X_EXT_NATT
) != 0) hdrsiz
+= sizeof(struct udphdr
) + 4;
164 * sizeof(struct newesp) > sizeof(struct esp). (8)
165 * esp_max_ivlen() = max ivlen for CBC mode
166 * 17 = (maximum padding length without random padding length)
167 * + (Pad Length field) + (Next Header field).
168 * 16 = maximum ICV we support.
169 * sizeof(struct udphdr) in case NAT traversal is used
171 return sizeof(struct newesp
) + esp_max_ivlen() + 17 + 16 + sizeof(struct udphdr
);
175 * Modify the packet so that the payload is encrypted.
176 * The mbuf (m) must start with IPv4 or IPv6 header.
177 * On failure, free the given mbuf and return NULL.
182 * IP ......... payload
183 * during the encryption:
184 * m nexthdrp mprev md
186 * IP ............... esp iv payload pad padlen nxthdr
187 * <--><-><------><--------------->
188 * esplen plen extendsiz
192 * <-----------------> espoff
195 esp_output(m
, nexthdrp
, md
, isr
, af
)
199 struct ipsecrequest
*isr
;
205 struct esptail
*esptail
;
206 struct secasvar
*sav
= isr
->sav
;
207 const struct esp_algorithm
*algo
;
210 size_t plen
; /*payload length to be encrypted*/
216 struct ipsecstat
*stat
;
217 struct udphdr
*udp
= NULL
;
218 int udp_encapsulate
= (sav
->flags
& SADB_X_EXT_NATT
&& af
== AF_INET
&&
219 (esp_udp_encap_port
& 0xFFFF) != 0);
221 KERNEL_DEBUG(DBG_FNC_ESPOUT
| DBG_FUNC_START
, sav
->ivlen
,0,0,0,0);
236 ipseclog((LOG_ERR
, "esp_output: unsupported af %d\n", af
));
237 KERNEL_DEBUG(DBG_FNC_ESPOUT
| DBG_FUNC_END
, 1,0,0,0,0);
238 return 0; /* no change at all */
241 /* some sanity check */
242 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && !sav
->replay
) {
249 ip
= mtod(m
, struct ip
*);
250 ipseclog((LOG_DEBUG
, "esp4_output: internal error: "
251 "sav->replay is null: %x->%x, SPI=%u\n",
252 (u_int32_t
)ntohl(ip
->ip_src
.s_addr
),
253 (u_int32_t
)ntohl(ip
->ip_dst
.s_addr
),
254 (u_int32_t
)ntohl(sav
->spi
)));
255 ipsecstat
.out_inval
++;
261 ipseclog((LOG_DEBUG
, "esp6_output: internal error: "
262 "sav->replay is null: SPI=%u\n",
263 (u_int32_t
)ntohl(sav
->spi
)));
264 ipsec6stat
.out_inval
++;
268 panic("esp_output: should not reach here");
271 KERNEL_DEBUG(DBG_FNC_ESPOUT
| DBG_FUNC_END
, 2,0,0,0,0);
275 algo
= esp_algorithm_lookup(sav
->alg_enc
);
277 ipseclog((LOG_ERR
, "esp_output: unsupported algorithm: "
278 "SPI=%u\n", (u_int32_t
)ntohl(sav
->spi
)));
280 KERNEL_DEBUG(DBG_FNC_ESPOUT
| DBG_FUNC_END
, 3,0,0,0,0);
287 panic("invalid ivlen");
293 * XXX inserts ESP header right after IPv4 header. should
294 * chase the header chain.
295 * XXX sequential number
298 struct ip
*ip
= NULL
;
301 struct ip6_hdr
*ip6
= NULL
;
303 size_t esplen
; /* sizeof(struct esp/newesp) */
304 size_t esphlen
; /* sizeof(struct esp/newesp) + ivlen */
305 size_t hlen
= 0; /* ip header len */
307 if (sav
->flags
& SADB_X_EXT_OLD
) {
309 esplen
= sizeof(struct esp
);
312 if (sav
->flags
& SADB_X_EXT_DERIV
)
313 esplen
= sizeof(struct esp
);
315 esplen
= sizeof(struct newesp
);
317 esphlen
= esplen
+ ivlen
;
319 for (mprev
= m
; mprev
&& mprev
->m_next
!= md
; mprev
= mprev
->m_next
)
321 if (mprev
== NULL
|| mprev
->m_next
!= md
) {
322 ipseclog((LOG_DEBUG
, "esp%d_output: md is not in chain\n",
325 KERNEL_DEBUG(DBG_FNC_ESPOUT
| DBG_FUNC_END
, 4,0,0,0,0);
330 for (n
= md
; n
; n
= n
->m_next
)
336 ip
= mtod(m
, struct ip
*);
338 hlen
= IP_VHL_HL(ip
->ip_vhl
) << 2;
340 hlen
= ip
->ip_hl
<< 2;
346 ip6
= mtod(m
, struct ip6_hdr
*);
352 /* make the packet over-writable */
353 mprev
->m_next
= NULL
;
354 if ((md
= ipsec_copypkt(md
)) == NULL
) {
361 espoff
= m
->m_pkthdr
.len
- plen
;
363 if (udp_encapsulate
) {
364 esphlen
+= sizeof(struct udphdr
);
365 espoff
+= sizeof(struct udphdr
);
369 * grow the mbuf to accomodate ESP header.
370 * before: IP ... payload
371 * after: IP ... [UDP] ESP IV payload
373 if (M_LEADINGSPACE(md
) < esphlen
|| (md
->m_flags
& M_EXT
) != 0) {
374 MGET(n
, M_DONTWAIT
, MT_DATA
);
383 m
->m_pkthdr
.len
+= esphlen
;
384 if (udp_encapsulate
) {
385 udp
= mtod(n
, struct udphdr
*);
386 esp
= (struct esp
*)((caddr_t
)udp
+ sizeof(struct udphdr
));
388 esp
= mtod(n
, struct esp
*);
391 md
->m_len
+= esphlen
;
392 md
->m_data
-= esphlen
;
393 m
->m_pkthdr
.len
+= esphlen
;
394 esp
= mtod(md
, struct esp
*);
395 if (udp_encapsulate
) {
396 udp
= mtod(md
, struct udphdr
*);
397 esp
= (struct esp
*)((caddr_t
)udp
+ sizeof(struct udphdr
));
399 esp
= mtod(md
, struct esp
*);
406 if (esphlen
< (IP_MAXPACKET
- ntohs(ip
->ip_len
)))
407 ip
->ip_len
= htons(ntohs(ip
->ip_len
) + esphlen
);
410 "IPv4 ESP output: size exceeds limit\n"));
411 ipsecstat
.out_inval
++;
420 /* total packet length will be computed in ip6_output() */
426 /* initialize esp header. */
428 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0) {
430 nesp
= (struct newesp
*)esp
;
431 if (sav
->replay
->count
== ~0) {
432 if ((sav
->flags
& SADB_X_EXT_CYCSEQ
) == 0) {
433 /* XXX Is it noisy ? */
434 ipseclog((LOG_WARNING
,
435 "replay counter overflowed. %s\n",
436 ipsec_logsastr(sav
)));
439 KERNEL_DEBUG(DBG_FNC_ESPOUT
| DBG_FUNC_END
, 5,0,0,0,0);
443 sav
->replay
->count
++;
445 * XXX sequence number must not be cycled, if the SA is
446 * installed by IKE daemon.
448 nesp
->esp_seq
= htonl(sav
->replay
->count
);
453 * find the last mbuf. make some room for ESP trailer.
456 struct ip
*ip
= NULL
;
464 padbound
= algo
->padbound
;
467 /* ESP packet, including nxthdr field, must be length of 4n */
471 extendsiz
= padbound
- (plen
% padbound
);
473 extendsiz
= padbound
+ 1;
479 randpadmax
= ip4_esp_randpad
;
484 randpadmax
= ip6_esp_randpad
;
491 if (randpadmax
< 0 || plen
+ extendsiz
>= randpadmax
)
497 randpadmax
= (randpadmax
/ padbound
) * padbound
;
498 n
= (randpadmax
- plen
+ extendsiz
) / padbound
;
501 n
= (random() % n
) * padbound
;
506 * make sure we do not pad too much.
507 * MLEN limitation comes from the trailer attachment
509 * 256 limitation comes from sequential padding.
510 * also, the 1-octet length field in ESP trailer imposes
511 * limitation (but is less strict than sequential padding
512 * as length field do not count the last 2 octets).
514 if (extendsiz
+ n
<= MLEN
&& extendsiz
+ n
< 256)
519 if (extendsiz
> MLEN
|| extendsiz
>= 256)
520 panic("extendsiz too big in esp_output");
528 * if M_EXT, the external mbuf data may be shared among
529 * two consequtive TCP packets, and it may be unsafe to use the
532 if (!(n
->m_flags
& M_EXT
) && extendsiz
< M_TRAILINGSPACE(n
)) {
533 extend
= mtod(n
, u_char
*) + n
->m_len
;
534 n
->m_len
+= extendsiz
;
535 m
->m_pkthdr
.len
+= extendsiz
;
539 MGET(nn
, M_DONTWAIT
, MT_DATA
);
541 ipseclog((LOG_DEBUG
, "esp%d_output: can't alloc mbuf",
547 extend
= mtod(nn
, u_char
*);
548 nn
->m_len
= extendsiz
;
552 m
->m_pkthdr
.len
+= extendsiz
;
554 switch (sav
->flags
& SADB_X_EXT_PMASK
) {
555 case SADB_X_EXT_PRAND
:
556 key_randomfill(extend
, extendsiz
);
558 case SADB_X_EXT_PZERO
:
559 bzero(extend
, extendsiz
);
561 case SADB_X_EXT_PSEQ
:
562 for (i
= 0; i
< extendsiz
; i
++)
563 extend
[i
] = (i
+ 1) & 0xff;
568 if (udp_encapsulate
) {
569 *nexthdrp
= IPPROTO_UDP
;
571 /* Fill out the UDP header */
572 udp
->uh_sport
= ntohs((u_short
)esp_udp_encap_port
);
573 udp
->uh_dport
= ntohs(sav
->remote_ike_port
);
574 // udp->uh_len set later, after all length tweaks are complete
577 /* Update last sent so we know if we need to send keepalive */
578 sav
->natt_last_activity
= natt_now
;
580 *nexthdrp
= IPPROTO_ESP
;
583 /* initialize esp trailer. */
584 esptail
= (struct esptail
*)
585 (mtod(n
, u_int8_t
*) + n
->m_len
- sizeof(struct esptail
));
586 esptail
->esp_nxt
= nxt
;
587 esptail
->esp_padlen
= extendsiz
- 2;
589 /* modify IP header (for ESP header part only) */
593 ip
= mtod(m
, struct ip
*);
594 if (extendsiz
< (IP_MAXPACKET
- ntohs(ip
->ip_len
)))
595 ip
->ip_len
= htons(ntohs(ip
->ip_len
) + extendsiz
);
598 "IPv4 ESP output: size exceeds limit\n"));
599 ipsecstat
.out_inval
++;
608 /* total packet length will be computed in ip6_output() */
615 * pre-compute and cache intermediate key
617 error
= esp_schedule(algo
, sav
);
625 * encrypt the packet, based on security association
626 * and the algorithm specified.
629 panic("internal error: no encrypt function");
630 KERNEL_DEBUG(DBG_FNC_ENCRYPT
| DBG_FUNC_START
, 0,0,0,0,0);
631 if ((*algo
->encrypt
)(m
, espoff
, plen
+ extendsiz
, sav
, algo
, ivlen
)) {
632 /* m is already freed */
633 ipseclog((LOG_ERR
, "packet encryption failure\n"));
636 KERNEL_DEBUG(DBG_FNC_ENCRYPT
| DBG_FUNC_END
, 1,error
,0,0,0);
639 KERNEL_DEBUG(DBG_FNC_ENCRYPT
| DBG_FUNC_END
, 2,0,0,0,0);
642 * calculate ICV if required.
648 if (sav
->key_auth
== SADB_AALG_NONE
)
652 const struct ah_algorithm
*aalgo
;
653 u_char authbuf
[AH_MAXSUMSIZE
];
661 aalgo
= ah_algorithm_lookup(sav
->alg_auth
);
664 siz
= ((aalgo
->sumsiz
)(sav
) + 3) & ~(4 - 1);
665 if (AH_MAXSUMSIZE
< siz
)
666 panic("assertion failed for AH_MAXSUMSIZE");
668 if (esp_auth(m
, espoff
, m
->m_pkthdr
.len
- espoff
, sav
, authbuf
)) {
669 ipseclog((LOG_ERR
, "ESP checksum generation failure\n"));
680 if (!(n
->m_flags
& M_EXT
) && siz
< M_TRAILINGSPACE(n
)) { /* XXX */
682 m
->m_pkthdr
.len
+= siz
;
683 p
= mtod(n
, u_char
*) + n
->m_len
- siz
;
687 MGET(nn
, M_DONTWAIT
, MT_DATA
);
689 ipseclog((LOG_DEBUG
, "can't alloc mbuf in esp%d_output",
699 m
->m_pkthdr
.len
+= siz
;
700 p
= mtod(nn
, u_char
*);
702 bcopy(authbuf
, p
, siz
);
704 /* modify IP header (for ESP header part only) */
708 ip
= mtod(m
, struct ip
*);
709 if (siz
< (IP_MAXPACKET
- ntohs(ip
->ip_len
)))
710 ip
->ip_len
= htons(ntohs(ip
->ip_len
) + siz
);
713 "IPv4 ESP output: size exceeds limit\n"));
714 ipsecstat
.out_inval
++;
723 /* total packet length will be computed in ip6_output() */
729 if (udp_encapsulate
) {
731 ip
= mtod(m
, struct ip
*);
732 udp
->uh_ulen
= htons(ntohs(ip
->ip_len
) - (IP_VHL_HL(ip
->ip_vhl
) << 2));
739 "NULL mbuf after encryption in esp%d_output", afnumber
));
742 stat
->out_esphist
[sav
->alg_enc
]++;
743 key_sa_recordxfer(sav
, m
);
744 KERNEL_DEBUG(DBG_FNC_ESPOUT
| DBG_FUNC_END
, 6,0,0,0,0);
749 KERNEL_DEBUG(DBG_FNC_ESPOUT
| DBG_FUNC_END
, 7,error
,0,0,0);
752 panic("something bad in esp_output");
760 struct ipsecrequest
*isr
;
763 if (m
->m_len
< sizeof(struct ip
)) {
764 ipseclog((LOG_DEBUG
, "esp4_output: first mbuf too short\n"));
768 ip
= mtod(m
, struct ip
*);
769 /* XXX assumes that m->m_next points to payload */
770 return esp_output(m
, &ip
->ip_p
, m
->m_next
, isr
, AF_INET
);
776 esp6_output(m
, nexthdrp
, md
, isr
)
780 struct ipsecrequest
*isr
;
782 if (m
->m_len
< sizeof(struct ip6_hdr
)) {
783 ipseclog((LOG_DEBUG
, "esp6_output: first mbuf too short\n"));
787 return esp_output(m
, nexthdrp
, md
, isr
, AF_INET6
);