Consolidate usage of MIN/MAX().
[dragonfly.git] / sys / netinet6 / esp_output.c
1 /*      $FreeBSD: src/sys/netinet6/esp_output.c,v 1.1.2.4 2003/05/06 06:46:58 suz Exp $ */
2 /*      $DragonFly: src/sys/netinet6/esp_output.c,v 1.2 2003/06/17 04:28:51 dillon Exp $        */
3 /*      $KAME: esp_output.c,v 1.44 2001/07/26 06:53:15 jinmei Exp $     */
4
5 /*
6  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the project nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include "opt_inet.h"
35 #include "opt_inet6.h"
36
37 /*
38  * RFC1827/2406 Encapsulated Security Payload.
39  */
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/mbuf.h>
44 #include <sys/domain.h>
45 #include <sys/protosw.h>
46 #include <sys/socket.h>
47 #include <sys/socketvar.h>
48 #include <sys/errno.h>
49 #include <sys/time.h>
50 #include <sys/syslog.h>
51
52 #include <net/if.h>
53 #include <net/route.h>
54
55 #include <netinet/in.h>
56 #include <netinet/in_systm.h>
57 #include <netinet/ip.h>
58 #include <netinet/in_var.h>
59
60 #ifdef INET6
61 #include <netinet/ip6.h>
62 #include <netinet6/ip6_var.h>
63 #include <netinet/icmp6.h>
64 #endif
65
66 #include <netinet6/ipsec.h>
67 #ifdef INET6
68 #include <netinet6/ipsec6.h>
69 #endif
70 #include <netinet6/ah.h>
71 #ifdef INET6
72 #include <netinet6/ah6.h>
73 #endif
74 #include <netinet6/esp.h>
75 #ifdef INET6
76 #include <netinet6/esp6.h>
77 #endif
78 #include <netkey/key.h>
79 #include <netkey/keydb.h>
80
81 #include <net/net_osdep.h>
82
83 static int esp_output __P((struct mbuf *, u_char *, struct mbuf *,
84         struct ipsecrequest *, int));
85
86 /*
87  * compute ESP header size.
88  */
89 size_t
90 esp_hdrsiz(isr)
91         struct ipsecrequest *isr;
92 {
93         struct secasvar *sav;
94         const struct esp_algorithm *algo;
95         const struct ah_algorithm *aalgo;
96         size_t ivlen;
97         size_t authlen;
98         size_t hdrsiz;
99
100         /* sanity check */
101         if (isr == NULL)
102                 panic("esp_hdrsiz: NULL was passed.");
103
104         sav = isr->sav;
105
106         if (isr->saidx.proto != IPPROTO_ESP)
107                 panic("unsupported mode passed to esp_hdrsiz");
108
109         if (sav == NULL)
110                 goto estimate;
111         if (sav->state != SADB_SASTATE_MATURE
112          && sav->state != SADB_SASTATE_DYING)
113                 goto estimate;
114
115         /* we need transport mode ESP. */
116         algo = esp_algorithm_lookup(sav->alg_enc);
117         if (!algo)
118                 goto estimate;
119         ivlen = sav->ivlen;
120         if (ivlen < 0)
121                 goto estimate;
122
123         /*
124          * XXX
125          * right now we don't calcurate the padding size.  simply
126          * treat the padding size as constant, for simplicity.
127          *
128          * XXX variable size padding support
129          */
130         if (sav->flags & SADB_X_EXT_OLD) {
131                 /* RFC 1827 */
132                 hdrsiz = sizeof(struct esp) + ivlen + 9;
133         } else {
134                 /* RFC 2406 */
135                 aalgo = ah_algorithm_lookup(sav->alg_auth);
136                 if (aalgo && sav->replay && sav->key_auth)
137                         authlen = (aalgo->sumsiz)(sav);
138                 else
139                         authlen = 0;
140                 hdrsiz = sizeof(struct newesp) + ivlen + 9 + authlen;
141         }
142
143         return hdrsiz;
144
145    estimate:
146         /*
147          * ASSUMING:
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.
153          */
154         return sizeof(struct newesp) + esp_max_ivlen() + 9 + 16;
155 }
156
157 /*
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.
161  *
162  * on invocation:
163  *      m   nexthdrp md
164  *      v   v        v
165  *      IP ......... payload
166  * during the encryption:
167  *      m   nexthdrp mprev md
168  *      v   v        v     v
169  *      IP ............... esp iv payload pad padlen nxthdr
170  *                         <--><-><------><--------------->
171  *                         esplen plen    extendsiz
172  *                             ivlen
173  *                         <-----> esphlen
174  *      <-> hlen
175  *      <-----------------> espoff
176  */
177 static int
178 esp_output(m, nexthdrp, md, isr, af)
179         struct mbuf *m;
180         u_char *nexthdrp;
181         struct mbuf *md;
182         struct ipsecrequest *isr;
183         int af;
184 {
185         struct mbuf *n;
186         struct mbuf *mprev;
187         struct esp *esp;
188         struct esptail *esptail;
189         struct secasvar *sav = isr->sav;
190         const struct esp_algorithm *algo;
191         u_int32_t spi;
192         u_int8_t nxt = 0;
193         size_t plen;    /* payload length to be encrypted */
194         size_t espoff;
195         int ivlen;
196         int afnumber;
197         size_t extendsiz;
198         int error = 0;
199         struct ipsecstat *stat;
200
201         switch (af) {
202 #ifdef INET
203         case AF_INET:
204                 afnumber = 4;
205                 stat = &ipsecstat;
206                 break;
207 #endif
208 #ifdef INET6
209         case AF_INET6:
210                 afnumber = 6;
211                 stat = &ipsec6stat;
212                 break;
213 #endif
214         default:
215                 ipseclog((LOG_ERR, "esp_output: unsupported af %d\n", af));
216                 return 0;       /* no change at all */
217         }
218
219         /* some sanity check */
220         if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) {
221                 switch (af) {
222 #ifdef INET
223                 case AF_INET:
224                     {
225                         struct ip *ip;
226
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++;
234                         break;
235                     }
236 #endif /* INET */
237 #ifdef INET6
238                 case AF_INET6:
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++;
243                         break;
244 #endif /* INET6 */
245                 default:
246                         panic("esp_output: should not reach here");
247                 }
248                 m_freem(m);
249                 return EINVAL;
250         }
251
252         algo = esp_algorithm_lookup(sav->alg_enc);
253         if (!algo) {
254                 ipseclog((LOG_ERR, "esp_output: unsupported algorithm: "
255                     "SPI=%u\n", (u_int32_t)ntohl(sav->spi)));
256                 m_freem(m);
257                 return EINVAL;
258         }
259         spi = sav->spi;
260         ivlen = sav->ivlen;
261         /* should be okey */
262         if (ivlen < 0) {
263                 panic("invalid ivlen");
264         }
265
266     {
267         /*
268          * insert ESP header.
269          * XXX inserts ESP header right after IPv4 header.  should
270          * chase the header chain.
271          * XXX sequential number
272          */
273 #ifdef INET
274         struct ip *ip = NULL;
275 #endif
276 #ifdef INET6
277         struct ip6_hdr *ip6 = NULL;
278 #endif
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 */
282
283         if (sav->flags & SADB_X_EXT_OLD) {
284                 /* RFC 1827 */
285                 esplen = sizeof(struct esp);
286         } else {
287                 /* RFC 2406 */
288                 if (sav->flags & SADB_X_EXT_DERIV)
289                         esplen = sizeof(struct esp);
290                 else
291                         esplen = sizeof(struct newesp);
292         }
293         esphlen = esplen + ivlen;
294
295         for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
296                 ;
297         if (mprev == NULL || mprev->m_next != md) {
298                 ipseclog((LOG_DEBUG, "esp%d_output: md is not in chain\n",
299                     afnumber));
300                 m_freem(m);
301                 return EINVAL;
302         }
303
304         plen = 0;
305         for (n = md; n; n = n->m_next)
306                 plen += n->m_len;
307
308         switch (af) {
309 #ifdef INET
310         case AF_INET:
311                 ip = mtod(m, struct ip *);
312 #ifdef _IP_VHL
313                 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
314 #else
315                 hlen = ip->ip_hl << 2;
316 #endif
317                 break;
318 #endif
319 #ifdef INET6
320         case AF_INET6:
321                 ip6 = mtod(m, struct ip6_hdr *);
322                 hlen = sizeof(*ip6);
323                 break;
324 #endif
325         }
326
327         /* make the packet over-writable */
328         mprev->m_next = NULL;
329         if ((md = ipsec_copypkt(md)) == NULL) {
330                 m_freem(m);
331                 error = ENOBUFS;
332                 goto fail;
333         }
334         mprev->m_next = md;
335
336         espoff = m->m_pkthdr.len - plen;
337
338         /*
339          * grow the mbuf to accomodate ESP header.
340          * before: IP ... payload
341          * after:  IP ... ESP IV payload
342          */
343         if (M_LEADINGSPACE(md) < esphlen || (md->m_flags & M_EXT) != 0) {
344                 MGET(n, M_DONTWAIT, MT_DATA);
345                 if (!n) {
346                         m_freem(m);
347                         error = ENOBUFS;
348                         goto fail;
349                 }
350                 n->m_len = esphlen;
351                 mprev->m_next = n;
352                 n->m_next = md;
353                 m->m_pkthdr.len += esphlen;
354                 esp = mtod(n, struct esp *);
355         } else {
356                 md->m_len += esphlen;
357                 md->m_data -= esphlen;
358                 m->m_pkthdr.len += esphlen;
359                 esp = mtod(md, struct esp *);
360         }
361         
362         nxt = *nexthdrp;
363         *nexthdrp = IPPROTO_ESP;
364         switch (af) {
365 #ifdef INET
366         case AF_INET:
367                 if (esphlen < (IP_MAXPACKET - ntohs(ip->ip_len)))
368                         ip->ip_len = htons(ntohs(ip->ip_len) + esphlen);
369                 else {
370                         ipseclog((LOG_ERR,
371                             "IPv4 ESP output: size exceeds limit\n"));
372                         ipsecstat.out_inval++;
373                         m_freem(m);
374                         error = EMSGSIZE;
375                         goto fail;
376                 }
377                 break;
378 #endif
379 #ifdef INET6
380         case AF_INET6:
381                 /* total packet length will be computed in ip6_output() */
382                 break;
383 #endif
384         }
385     }
386
387         /* initialize esp header. */
388         esp->esp_spi = spi;
389         if ((sav->flags & SADB_X_EXT_OLD) == 0) {
390                 struct newesp *nesp;
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)));
398                                 stat->out_inval++;
399                                 m_freem(m);
400                                 return EINVAL;
401                         }
402                 }
403                 sav->replay->count++;
404                 /*
405                  * XXX sequence number must not be cycled, if the SA is
406                  * installed by IKE daemon.
407                  */
408                 nesp->esp_seq = htonl(sav->replay->count);
409         }
410
411     {
412         /*
413          * find the last mbuf. make some room for ESP trailer.
414          */
415 #ifdef INET
416         struct ip *ip = NULL;
417 #endif
418         size_t padbound;
419         u_char *extend;
420         int i;
421         int randpadmax;
422
423         if (algo->padbound)
424                 padbound = algo->padbound;
425         else
426                 padbound = 4;
427         /* ESP packet, including nxthdr field, must be length of 4n */
428         if (padbound < 4)
429                 padbound = 4;
430         
431         extendsiz = padbound - (plen % padbound);
432         if (extendsiz == 1)
433                 extendsiz = padbound + 1;
434
435         /* random padding */
436         switch (af) {
437 #ifdef INET
438         case AF_INET:
439                 randpadmax = ip4_esp_randpad;
440                 break;
441 #endif
442 #ifdef INET6
443         case AF_INET6:
444                 randpadmax = ip6_esp_randpad;
445                 break;
446 #endif
447         default:
448                 randpadmax = -1;
449                 break;
450         }
451         if (randpadmax < 0 || plen + extendsiz >= randpadmax)
452                 ;
453         else {
454                 int n;
455
456                 /* round */
457                 randpadmax = (randpadmax / padbound) * padbound;
458                 n = (randpadmax - plen + extendsiz) / padbound;
459
460                 if (n > 0)
461                         n = (random() % n) * padbound;
462                 else
463                         n = 0;
464
465                 /*
466                  * make sure we do not pad too much.
467                  * MLEN limitation comes from the trailer attachment
468                  * code below.
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).
473                  */
474                 if (extendsiz + n <= MLEN && extendsiz + n < 256)
475                         extendsiz += n;
476         }
477
478 #ifdef DIAGNOSTIC
479         if (extendsiz > MLEN || extendsiz >= 256)
480                 panic("extendsiz too big in esp_output");
481 #endif
482
483         n = m;
484         while (n->m_next)
485                 n = n->m_next;
486
487         /*
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
490          * trailing space.
491          */
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;
496         } else {
497                 struct mbuf *nn;
498
499                 MGET(nn, M_DONTWAIT, MT_DATA);
500                 if (!nn) {
501                         ipseclog((LOG_DEBUG, "esp%d_output: can't alloc mbuf",
502                             afnumber));
503                         m_freem(m);
504                         error = ENOBUFS;
505                         goto fail;
506                 }
507                 extend = mtod(nn, u_char *);
508                 nn->m_len = extendsiz;
509                 nn->m_next = NULL;
510                 n->m_next = nn;
511                 n = nn;
512                 m->m_pkthdr.len += extendsiz;
513         }
514         switch (sav->flags & SADB_X_EXT_PMASK) {
515         case SADB_X_EXT_PRAND:
516                 key_randomfill(extend, extendsiz);
517                 break;
518         case SADB_X_EXT_PZERO:
519                 bzero(extend, extendsiz);
520                 break;
521         case SADB_X_EXT_PSEQ:
522                 for (i = 0; i < extendsiz; i++)
523                         extend[i] = (i + 1) & 0xff;
524                 break;
525         }
526
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;
532
533         /* modify IP header (for ESP header part only) */
534         switch (af) {
535 #ifdef INET
536         case AF_INET:
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);
540                 else {
541                         ipseclog((LOG_ERR,
542                             "IPv4 ESP output: size exceeds limit\n"));
543                         ipsecstat.out_inval++;
544                         m_freem(m);
545                         error = EMSGSIZE;
546                         goto fail;
547                 }
548                 break;
549 #endif
550 #ifdef INET6
551         case AF_INET6:
552                 /* total packet length will be computed in ip6_output() */
553                 break;
554 #endif
555         }
556     }
557
558         /*
559          * pre-compute and cache intermediate key
560          */
561         error = esp_schedule(algo, sav);
562         if (error) {
563                 m_freem(m);
564                 stat->out_inval++;
565                 goto fail;
566         }
567
568         /*
569          * encrypt the packet, based on security association
570          * and the algorithm specified.
571          */
572         if (!algo->encrypt)
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"));
577                 stat->out_inval++;
578                 error = EINVAL;
579                 goto fail;
580         }
581
582         /*
583          * calculate ICV if required.
584          */
585         if (!sav->replay)
586                 goto noantireplay;
587         if (!sav->key_auth)
588                 goto noantireplay;
589         if (sav->key_auth == SADB_AALG_NONE)
590                 goto noantireplay;
591
592     {
593         const struct ah_algorithm *aalgo;
594         u_char authbuf[AH_MAXSUMSIZE];
595         struct mbuf *n;
596         u_char *p;
597         size_t siz;
598 #ifdef INET
599         struct ip *ip;
600 #endif
601
602         aalgo = ah_algorithm_lookup(sav->alg_auth);
603         if (!aalgo)
604                 goto noantireplay;
605         siz = ((aalgo->sumsiz)(sav) + 3) & ~(4 - 1);
606         if (AH_MAXSUMSIZE < siz)
607                 panic("assertion failed for AH_MAXSUMSIZE");
608
609         if (esp_auth(m, espoff, m->m_pkthdr.len - espoff, sav, authbuf)) {
610                 ipseclog((LOG_ERR, "ESP checksum generation failure\n"));
611                 m_freem(m);
612                 error = EINVAL;
613                 stat->out_inval++;
614                 goto fail;
615         }
616
617         n = m;
618         while (n->m_next)
619                 n = n->m_next;
620
621         if (!(n->m_flags & M_EXT) && siz < M_TRAILINGSPACE(n)) { /* XXX */
622                 n->m_len += siz;
623                 m->m_pkthdr.len += siz;
624                 p = mtod(n, u_char *) + n->m_len - siz;
625         } else {
626                 struct mbuf *nn;
627
628                 MGET(nn, M_DONTWAIT, MT_DATA);
629                 if (!nn) {
630                         ipseclog((LOG_DEBUG, "can't alloc mbuf in esp%d_output",
631                             afnumber));
632                         m_freem(m);
633                         error = ENOBUFS;
634                         goto fail;
635                 }
636                 nn->m_len = siz;
637                 nn->m_next = NULL;
638                 n->m_next = nn;
639                 n = nn;
640                 m->m_pkthdr.len += siz;
641                 p = mtod(nn, u_char *);
642         }
643         bcopy(authbuf, p, siz);
644
645         /* modify IP header (for ESP header part only) */
646         switch (af) {
647 #ifdef INET
648         case AF_INET:
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);
652                 else {
653                         ipseclog((LOG_ERR,
654                             "IPv4 ESP output: size exceeds limit\n"));
655                         ipsecstat.out_inval++;
656                         m_freem(m);
657                         error = EMSGSIZE;
658                         goto fail;
659                 }
660                 break;
661 #endif
662 #ifdef INET6
663         case AF_INET6:
664                 /* total packet length will be computed in ip6_output() */
665                 break;
666 #endif
667         }
668     }
669
670 noantireplay:
671         if (!m) {
672                 ipseclog((LOG_ERR,
673                     "NULL mbuf after encryption in esp%d_output", afnumber));
674         } else
675                 stat->out_success++;
676         stat->out_esphist[sav->alg_enc]++;
677         key_sa_recordxfer(sav, m);
678         return 0;
679
680 fail:
681 #if 1
682         return error;
683 #else
684         panic("something bad in esp_output");
685 #endif
686 }
687
688 #ifdef INET
689 int
690 esp4_output(m, isr)
691         struct mbuf *m;
692         struct ipsecrequest *isr;
693 {
694         struct ip *ip;
695         if (m->m_len < sizeof(struct ip)) {
696                 ipseclog((LOG_DEBUG, "esp4_output: first mbuf too short\n"));
697                 m_freem(m);
698                 return 0;
699         }
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);
703 }
704 #endif /* INET */
705
706 #ifdef INET6
707 int
708 esp6_output(m, nexthdrp, md, isr)
709         struct mbuf *m;
710         u_char *nexthdrp;
711         struct mbuf *md;
712         struct ipsecrequest *isr;
713 {
714         if (m->m_len < sizeof(struct ip6_hdr)) {
715                 ipseclog((LOG_DEBUG, "esp6_output: first mbuf too short\n"));
716                 m_freem(m);
717                 return 0;
718         }
719         return esp_output(m, nexthdrp, md, isr, AF_INET6);
720 }
721 #endif /* INET6 */