]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/esp_output.c
1 /* $KAME: esp_output.c,v 1.17 2000/02/22 14:04:15 itojun Exp $ */
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__)
38 * RFC1827/2406 Encapsulated Security Payload.
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/malloc.h>
45 #include <sys/domain.h>
46 #include <sys/protosw.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
49 #include <sys/errno.h>
51 #include <sys/kernel.h>
52 #include <sys/syslog.h>
55 #include <net/route.h>
57 #include <netinet/in.h>
58 #include <netinet/in_systm.h>
59 #include <netinet/ip.h>
60 #include <netinet/in_var.h>
63 #include <netinet/ip6.h>
64 #include <netinet6/ip6_var.h>
65 #include <netinet/icmp6.h>
68 #include <netinet6/ipsec.h>
69 #include <netinet6/ah.h>
70 #include <netinet6/esp.h>
71 #include <netkey/key.h>
72 #include <netkey/keydb.h>
73 #include <netkey/key_debug.h>
75 #include <net/net_osdep.h>
77 static int esp_output
__P((struct mbuf
*, u_char
*, struct mbuf
*,
78 struct ipsecrequest
*, int));
81 * compute ESP header size.
85 struct ipsecrequest
*isr
;
88 struct esp_algorithm
*algo
;
95 panic("esp_hdrsiz: NULL was passed.\n");
99 if (isr
->saidx
.proto
!= IPPROTO_ESP
)
100 panic("unsupported mode passed to esp_hdrsiz");
104 if (sav
->state
!= SADB_SASTATE_MATURE
105 && sav
->state
!= SADB_SASTATE_DYING
)
108 /* we need transport mode ESP. */
109 algo
= &esp_algorithms
[sav
->alg_enc
];
118 * right now we don't calcurate the padding size. simply
119 * treat the padding size as constant, for simplicity.
121 * XXX variable size padding support
123 if (sav
->flags
& SADB_X_EXT_OLD
) {
125 hdrsiz
= sizeof(struct esp
) + ivlen
+ 9;
128 if (sav
->replay
&& sav
->alg_auth
&& sav
->key_auth
)
129 authlen
= (*ah_algorithms
[sav
->alg_auth
].sumsiz
)(sav
);
132 hdrsiz
= sizeof(struct newesp
) + ivlen
+ 9 + authlen
;
140 * sizeof(struct newesp) > sizeof(struct esp).
141 * 8 = ivlen for CBC mode (RFC2451).
142 * 9 = (maximum padding length without random padding length)
143 * + (Pad Length field) + (Next Header field).
144 * 16 = maximum ICV we support.
146 return sizeof(struct newesp
) + 8 + 9 + 16;
150 * Modify the packet so that the payload is encrypted.
151 * The mbuf (m) must start with IPv4 or IPv6 header.
152 * On failure, free the given mbuf and return NULL.
157 * IP ......... payload
158 * during the encryption:
159 * m nexthdrp mprev md
161 * IP ............... esp iv payload pad padlen nxthdr
162 * <--><-><------><--------------->
163 * esplen plen extendsiz
167 * <-----------------> espoff
170 esp_output(m
, nexthdrp
, md
, isr
, af
)
174 struct ipsecrequest
*isr
;
180 struct esptail
*esptail
;
181 struct secasvar
*sav
= isr
->sav
;
182 struct esp_algorithm
*algo
;
185 size_t plen
; /*payload length to be encrypted*/
204 ipseclog((LOG_ERR
, "esp_output: unsupported af %d\n", af
));
205 return 0; /* no change at all */
208 /* some sanity check */
209 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && !sav
->replay
) {
216 ip
= mtod(m
, struct ip
*);
217 ipseclog((LOG_DEBUG
, "esp4_output: internal error: "
218 "sav->replay is null: %x->%x, SPI=%u\n",
219 (u_int32_t
)ntohl(ip
->ip_src
.s_addr
),
220 (u_int32_t
)ntohl(ip
->ip_dst
.s_addr
),
221 (u_int32_t
)ntohl(sav
->spi
)));
222 ipsecstat
.out_inval
++;
232 ip6
= mtod(m
, struct ip6_hdr
*);
233 ipseclog((LOG_DEBUG
, "esp6_output: internal error: "
234 "sav->replay is null: SPI=%u\n",
235 (u_int32_t
)ntohl(sav
->spi
)));
236 ipsec6stat
.out_inval
++;
244 algo
= &esp_algorithms
[sav
->alg_enc
]; /*XXX*/
249 panic("invalid ivlen");
255 * XXX inserts ESP header right after IPv4 header. should
256 * chase the header chain.
257 * XXX sequential number
260 struct ip
*ip
= NULL
;
263 struct ip6_hdr
*ip6
= NULL
;
265 size_t esplen
; /*sizeof(struct esp/newesp)*/
266 size_t esphlen
; /*sizeof(struct esp/newesp) + ivlen*/
267 size_t hlen
= 0; /*ip header len*/
269 if (sav
->flags
& SADB_X_EXT_OLD
) {
271 esplen
= sizeof(struct esp
);
274 if (sav
->flags
& SADB_X_EXT_DERIV
)
275 esplen
= sizeof(struct esp
);
277 esplen
= sizeof(struct newesp
);
279 esphlen
= esplen
+ ivlen
;
281 for (mprev
= m
; mprev
&& mprev
->m_next
!= md
; mprev
= mprev
->m_next
)
283 if (mprev
== NULL
|| mprev
->m_next
!= md
) {
284 ipseclog((LOG_DEBUG
, "esp%d_output: md is not in chain\n",
291 for (n
= md
; n
; n
= n
->m_next
)
297 ip
= mtod(m
, struct ip
*);
299 hlen
= IP_VHL_HL(ip
->ip_vhl
) << 2;
301 hlen
= ip
->ip_hl
<< 2;
307 ip6
= mtod(m
, struct ip6_hdr
*);
313 /* make the packet over-writable */
314 mprev
->m_next
= NULL
;
315 if ((md
= ipsec_copypkt(md
)) == NULL
) {
322 espoff
= m
->m_pkthdr
.len
- plen
;
325 * grow the mbuf to accomodate ESP header.
326 * before: IP ... payload
327 * after: IP ... ESP IV payload
329 if (M_LEADINGSPACE(md
) < esphlen
) {
330 MGET(n
, M_DONTWAIT
, MT_DATA
);
339 m
->m_pkthdr
.len
+= esphlen
;
340 esp
= mtod(n
, struct esp
*);
342 md
->m_len
+= esphlen
;
343 md
->m_data
-= esphlen
;
344 m
->m_pkthdr
.len
+= esphlen
;
345 esp
= mtod(md
, struct esp
*);
349 *nexthdrp
= IPPROTO_ESP
;
353 if (esphlen
< (IP_MAXPACKET
- ntohs(ip
->ip_len
)))
354 ip
->ip_len
= htons(ntohs(ip
->ip_len
) + esphlen
);
357 "IPv4 ESP output: size exceeds limit\n"));
358 ipsecstat
.out_inval
++;
367 /* total packet length will be computed in ip6_output() */
373 /* initialize esp header. */
375 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0) {
377 nesp
= (struct newesp
*)esp
;
378 if (sav
->replay
->count
== ~0) {
379 if ((sav
->flags
& SADB_X_EXT_CYCSEQ
) == 0) {
380 /* XXX Is it noisy ? */
381 ipseclog((LOG_WARNING
,
382 "replay counter overflowed. %s\n",
383 ipsec_logsastr(sav
)));
384 ipsecstat
.out_inval
++;
389 sav
->replay
->count
++;
391 * XXX sequence number must not be cycled, if the SA is
392 * installed by IKE daemon.
394 nesp
->esp_seq
= htonl(sav
->replay
->count
);
399 * find the last mbuf. make some room for ESP trailer.
400 * XXX new-esp authentication data
403 struct ip
*ip
= NULL
;
410 padbound
= algo
->padbound
;
413 /* ESP packet, including nxthdr field, must be length of 4n */
417 extendsiz
= padbound
- (plen
% padbound
);
419 extendsiz
= padbound
+ 1;
426 * if M_EXT, the external part may be shared among
427 * two consequtive TCP packets.
429 if (!(n
->m_flags
& M_EXT
) && extendsiz
< M_TRAILINGSPACE(n
)) {
430 extend
= mtod(n
, u_char
*) + n
->m_len
;
431 n
->m_len
+= extendsiz
;
432 m
->m_pkthdr
.len
+= extendsiz
;
436 MGET(nn
, M_DONTWAIT
, MT_DATA
);
438 ipseclog((LOG_DEBUG
, "esp%d_output: can't alloc mbuf",
444 extend
= mtod(nn
, u_char
*);
445 nn
->m_len
= extendsiz
;
449 m
->m_pkthdr
.len
+= extendsiz
;
451 switch (sav
->flags
& SADB_X_EXT_PMASK
) {
452 case SADB_X_EXT_PRAND
:
453 for (i
= 0; i
< extendsiz
; i
++)
454 extend
[i
] = random() & 0xff;
456 case SADB_X_EXT_PZERO
:
457 bzero(extend
, extendsiz
);
459 case SADB_X_EXT_PSEQ
:
460 for (i
= 0; i
< extendsiz
; i
++)
461 extend
[i
] = (i
+ 1) & 0xff;
465 /* initialize esp trailer. */
466 esptail
= (struct esptail
*)
467 (mtod(n
, u_int8_t
*) + n
->m_len
- sizeof(struct esptail
));
468 esptail
->esp_nxt
= nxt
;
469 esptail
->esp_padlen
= extendsiz
- 2;
471 /* modify IP header (for ESP header part only) */
475 ip
= mtod(m
, struct ip
*);
476 if (extendsiz
< (IP_MAXPACKET
- ntohs(ip
->ip_len
)))
477 ip
->ip_len
= htons(ntohs(ip
->ip_len
) + extendsiz
);
480 "IPv4 ESP output: size exceeds limit\n"));
481 ipsecstat
.out_inval
++;
490 /* total packet length will be computed in ip6_output() */
497 * encrypt the packet, based on security association
498 * and the algorithm specified.
501 panic("internal error: no encrypt function");
502 if ((*algo
->encrypt
)(m
, espoff
, plen
+ extendsiz
, sav
, algo
, ivlen
)) {
503 ipseclog((LOG_ERR
, "packet encryption failure\n"));
508 ipsecstat
.out_inval
++;
513 ipsec6stat
.out_inval
++;
522 * calculate ICV if required.
531 u_char authbuf
[AH_MAXSUMSIZE
];
537 siz
= (((*ah_algorithms
[sav
->alg_auth
].sumsiz
)(sav
) + 3) & ~(4 - 1));
538 if (AH_MAXSUMSIZE
< siz
)
539 panic("assertion failed for AH_MAXSUMSIZE");
541 if (esp_auth(m
, espoff
, m
->m_pkthdr
.len
- espoff
, sav
, authbuf
))
548 if (!(n
->m_flags
& M_EXT
) && siz
< M_TRAILINGSPACE(n
)) { /*XXX*/
550 m
->m_pkthdr
.len
+= siz
;
551 p
= mtod(n
, u_char
*) + n
->m_len
- siz
;
555 MGET(nn
, M_DONTWAIT
, MT_DATA
);
557 ipseclog((LOG_DEBUG
, "can't alloc mbuf in esp%d_output",
567 m
->m_pkthdr
.len
+= siz
;
568 p
= mtod(nn
, u_char
*);
570 bcopy(authbuf
, p
, siz
);
572 /* modify IP header (for ESP header part only) */
576 ip
= mtod(m
, struct ip
*);
577 if (siz
< (IP_MAXPACKET
- ntohs(ip
->ip_len
)))
578 ip
->ip_len
= htons(ntohs(ip
->ip_len
) + siz
);
581 "IPv4 ESP output: size exceeds limit\n"));
582 ipsecstat
.out_inval
++;
591 /* total packet length will be computed in ip6_output() */
600 "NULL mbuf after encryption in esp%d_output", afnumber
));
605 ipsecstat
.out_success
++;
610 ipsec6stat
.out_success
++;
618 ipsecstat
.out_esphist
[sav
->alg_enc
]++;
623 ipsec6stat
.out_esphist
[sav
->alg_enc
]++;
627 key_sa_recordxfer(sav
, m
);
634 panic("something bad in esp_output");
642 struct ipsecrequest
*isr
;
645 if (m
->m_len
< sizeof(struct ip
)) {
646 ipseclog((LOG_DEBUG
, "esp4_output: first mbuf too short\n"));
650 ip
= mtod(m
, struct ip
*);
651 /* XXX assumes that m->m_next points to payload */
652 return esp_output(m
, &ip
->ip_p
, m
->m_next
, isr
, AF_INET
);
658 esp6_output(m
, nexthdrp
, md
, isr
)
662 struct ipsecrequest
*isr
;
664 if (m
->m_len
< sizeof(struct ip6_hdr
)) {
665 ipseclog((LOG_DEBUG
, "esp6_output: first mbuf too short\n"));
669 return esp_output(m
, nexthdrp
, md
, isr
, AF_INET6
);