add the 'y' and 'Y' options to ps, and add the 'iac' keyword. The 'y'
[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.6 2004/06/02 14:43:01 eirikn 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 <netproto/key/key.h>
79 #include <netproto/key/keydb.h>
80
81 #include <net/net_osdep.h>
82
83 static int esp_output (struct mbuf *, u_char *, struct mbuf *,
84         struct ipsecrequest *, int);
85
86 /*
87  * compute ESP header size.
88  */
89 size_t
90 esp_hdrsiz(struct ipsecrequest *isr)
91 {
92         struct secasvar *sav;
93         const struct esp_algorithm *algo;
94         const struct ah_algorithm *aalgo;
95         size_t ivlen;
96         size_t authlen;
97         size_t hdrsiz;
98
99         /* sanity check */
100         if (isr == NULL)
101                 panic("esp_hdrsiz: NULL was passed.");
102
103         sav = isr->sav;
104
105         if (isr->saidx.proto != IPPROTO_ESP)
106                 panic("unsupported mode passed to esp_hdrsiz");
107
108         if (sav == NULL)
109                 goto estimate;
110         if (sav->state != SADB_SASTATE_MATURE
111          && sav->state != SADB_SASTATE_DYING)
112                 goto estimate;
113
114         /* we need transport mode ESP. */
115         algo = esp_algorithm_lookup(sav->alg_enc);
116         if (!algo)
117                 goto estimate;
118         ivlen = sav->ivlen;
119         if (ivlen < 0)
120                 goto estimate;
121
122         /*
123          * XXX
124          * right now we don't calcurate the padding size.  simply
125          * treat the padding size as constant, for simplicity.
126          *
127          * XXX variable size padding support
128          */
129         if (sav->flags & SADB_X_EXT_OLD) {
130                 /* RFC 1827 */
131                 hdrsiz = sizeof(struct esp) + ivlen + 9;
132         } else {
133                 /* RFC 2406 */
134                 aalgo = ah_algorithm_lookup(sav->alg_auth);
135                 if (aalgo && sav->replay && sav->key_auth)
136                         authlen = (aalgo->sumsiz)(sav);
137                 else
138                         authlen = 0;
139                 hdrsiz = sizeof(struct newesp) + ivlen + 9 + authlen;
140         }
141
142         return hdrsiz;
143
144    estimate:
145         /*
146          * ASSUMING:
147          *      sizeof(struct newesp) > sizeof(struct esp).
148          *      esp_max_ivlen() = max ivlen for CBC mode
149          *      9 = (maximum padding length without random padding length)
150          *         + (Pad Length field) + (Next Header field).
151          *      16 = maximum ICV we support.
152          */
153         return sizeof(struct newesp) + esp_max_ivlen() + 9 + 16;
154 }
155
156 /*
157  * Modify the packet so that the payload is encrypted.
158  * The mbuf (m) must start with IPv4 or IPv6 header.
159  * On failure, free the given mbuf and return NULL.
160  *
161  * on invocation:
162  *      m   nexthdrp md
163  *      v   v        v
164  *      IP ......... payload
165  * during the encryption:
166  *      m   nexthdrp mprev md
167  *      v   v        v     v
168  *      IP ............... esp iv payload pad padlen nxthdr
169  *                         <--><-><------><--------------->
170  *                         esplen plen    extendsiz
171  *                             ivlen
172  *                         <-----> esphlen
173  *      <-> hlen
174  *      <-----------------> espoff
175  */
176 static int
177 esp_output(struct mbuf *m, u_char *nexthdrp, struct mbuf *md,
178            struct ipsecrequest *isr, int af)
179 {
180         struct mbuf *n;
181         struct mbuf *mprev;
182         struct esp *esp;
183         struct esptail *esptail;
184         struct secasvar *sav = isr->sav;
185         const struct esp_algorithm *algo;
186         u_int32_t spi;
187         u_int8_t nxt = 0;
188         size_t plen;    /* payload length to be encrypted */
189         size_t espoff;
190         int ivlen;
191         int afnumber;
192         size_t extendsiz;
193         int error = 0;
194         struct ipsecstat *stat;
195
196         switch (af) {
197 #ifdef INET
198         case AF_INET:
199                 afnumber = 4;
200                 stat = &ipsecstat;
201                 break;
202 #endif
203 #ifdef INET6
204         case AF_INET6:
205                 afnumber = 6;
206                 stat = &ipsec6stat;
207                 break;
208 #endif
209         default:
210                 ipseclog((LOG_ERR, "esp_output: unsupported af %d\n", af));
211                 return 0;       /* no change at all */
212         }
213
214         /* some sanity check */
215         if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) {
216                 switch (af) {
217 #ifdef INET
218                 case AF_INET:
219                     {
220                         struct ip *ip;
221
222                         ip = mtod(m, struct ip *);
223                         ipseclog((LOG_DEBUG, "esp4_output: internal error: "
224                                 "sav->replay is null: %x->%x, SPI=%u\n",
225                                 (u_int32_t)ntohl(ip->ip_src.s_addr),
226                                 (u_int32_t)ntohl(ip->ip_dst.s_addr),
227                                 (u_int32_t)ntohl(sav->spi)));
228                         ipsecstat.out_inval++;
229                         break;
230                     }
231 #endif /* INET */
232 #ifdef INET6
233                 case AF_INET6:
234                         ipseclog((LOG_DEBUG, "esp6_output: internal error: "
235                                 "sav->replay is null: SPI=%u\n",
236                                 (u_int32_t)ntohl(sav->spi)));
237                         ipsec6stat.out_inval++;
238                         break;
239 #endif /* INET6 */
240                 default:
241                         panic("esp_output: should not reach here");
242                 }
243                 m_freem(m);
244                 return EINVAL;
245         }
246
247         algo = esp_algorithm_lookup(sav->alg_enc);
248         if (!algo) {
249                 ipseclog((LOG_ERR, "esp_output: unsupported algorithm: "
250                     "SPI=%u\n", (u_int32_t)ntohl(sav->spi)));
251                 m_freem(m);
252                 return EINVAL;
253         }
254         spi = sav->spi;
255         ivlen = sav->ivlen;
256         /* should be okey */
257         if (ivlen < 0) {
258                 panic("invalid ivlen");
259         }
260
261     {
262         /*
263          * insert ESP header.
264          * XXX inserts ESP header right after IPv4 header.  should
265          * chase the header chain.
266          * XXX sequential number
267          */
268 #ifdef INET
269         struct ip *ip = NULL;
270 #endif
271 #ifdef INET6
272         struct ip6_hdr *ip6 = NULL;
273 #endif
274         size_t esplen;  /* sizeof(struct esp/newesp) */
275         size_t esphlen; /* sizeof(struct esp/newesp) + ivlen */
276         size_t hlen = 0;        /* ip header len */
277
278         if (sav->flags & SADB_X_EXT_OLD) {
279                 /* RFC 1827 */
280                 esplen = sizeof(struct esp);
281         } else {
282                 /* RFC 2406 */
283                 if (sav->flags & SADB_X_EXT_DERIV)
284                         esplen = sizeof(struct esp);
285                 else
286                         esplen = sizeof(struct newesp);
287         }
288         esphlen = esplen + ivlen;
289
290         for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
291                 ;
292         if (mprev == NULL || mprev->m_next != md) {
293                 ipseclog((LOG_DEBUG, "esp%d_output: md is not in chain\n",
294                     afnumber));
295                 m_freem(m);
296                 return EINVAL;
297         }
298
299         plen = 0;
300         for (n = md; n; n = n->m_next)
301                 plen += n->m_len;
302
303         switch (af) {
304 #ifdef INET
305         case AF_INET:
306                 ip = mtod(m, struct ip *);
307 #ifdef _IP_VHL
308                 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
309 #else
310                 hlen = ip->ip_hl << 2;
311 #endif
312                 break;
313 #endif
314 #ifdef INET6
315         case AF_INET6:
316                 ip6 = mtod(m, struct ip6_hdr *);
317                 hlen = sizeof(*ip6);
318                 break;
319 #endif
320         }
321
322         /* make the packet over-writable */
323         mprev->m_next = NULL;
324         if ((md = ipsec_copypkt(md)) == NULL) {
325                 m_freem(m);
326                 error = ENOBUFS;
327                 goto fail;
328         }
329         mprev->m_next = md;
330
331         espoff = m->m_pkthdr.len - plen;
332
333         /*
334          * grow the mbuf to accomodate ESP header.
335          * before: IP ... payload
336          * after:  IP ... ESP IV payload
337          */
338         if (M_LEADINGSPACE(md) < esphlen || (md->m_flags & M_EXT) != 0) {
339                 MGET(n, MB_DONTWAIT, MT_DATA);
340                 if (!n) {
341                         m_freem(m);
342                         error = ENOBUFS;
343                         goto fail;
344                 }
345                 n->m_len = esphlen;
346                 mprev->m_next = n;
347                 n->m_next = md;
348                 m->m_pkthdr.len += esphlen;
349                 esp = mtod(n, struct esp *);
350         } else {
351                 md->m_len += esphlen;
352                 md->m_data -= esphlen;
353                 m->m_pkthdr.len += esphlen;
354                 esp = mtod(md, struct esp *);
355         }
356         
357         nxt = *nexthdrp;
358         *nexthdrp = IPPROTO_ESP;
359         switch (af) {
360 #ifdef INET
361         case AF_INET:
362                 if (esphlen < (IP_MAXPACKET - ntohs(ip->ip_len)))
363                         ip->ip_len = htons(ntohs(ip->ip_len) + esphlen);
364                 else {
365                         ipseclog((LOG_ERR,
366                             "IPv4 ESP output: size exceeds limit\n"));
367                         ipsecstat.out_inval++;
368                         m_freem(m);
369                         error = EMSGSIZE;
370                         goto fail;
371                 }
372                 break;
373 #endif
374 #ifdef INET6
375         case AF_INET6:
376                 /* total packet length will be computed in ip6_output() */
377                 break;
378 #endif
379         }
380     }
381
382         /* initialize esp header. */
383         esp->esp_spi = spi;
384         if ((sav->flags & SADB_X_EXT_OLD) == 0) {
385                 struct newesp *nesp;
386                 nesp = (struct newesp *)esp;
387                 if (sav->replay->count == ~0) {
388                         if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) {
389                                 /* XXX Is it noisy ? */
390                                 ipseclog((LOG_WARNING,
391                                     "replay counter overflowed. %s\n",
392                                     ipsec_logsastr(sav)));
393                                 stat->out_inval++;
394                                 m_freem(m);
395                                 return EINVAL;
396                         }
397                 }
398                 sav->replay->count++;
399                 /*
400                  * XXX sequence number must not be cycled, if the SA is
401                  * installed by IKE daemon.
402                  */
403                 nesp->esp_seq = htonl(sav->replay->count);
404         }
405
406     {
407         /*
408          * find the last mbuf. make some room for ESP trailer.
409          */
410 #ifdef INET
411         struct ip *ip = NULL;
412 #endif
413         size_t padbound;
414         u_char *extend;
415         int i;
416         int randpadmax;
417
418         if (algo->padbound)
419                 padbound = algo->padbound;
420         else
421                 padbound = 4;
422         /* ESP packet, including nxthdr field, must be length of 4n */
423         if (padbound < 4)
424                 padbound = 4;
425         
426         extendsiz = padbound - (plen % padbound);
427         if (extendsiz == 1)
428                 extendsiz = padbound + 1;
429
430         /* random padding */
431         switch (af) {
432 #ifdef INET
433         case AF_INET:
434                 randpadmax = ip4_esp_randpad;
435                 break;
436 #endif
437 #ifdef INET6
438         case AF_INET6:
439                 randpadmax = ip6_esp_randpad;
440                 break;
441 #endif
442         default:
443                 randpadmax = -1;
444                 break;
445         }
446         if (randpadmax < 0 || plen + extendsiz >= randpadmax)
447                 ;
448         else {
449                 int n;
450
451                 /* round */
452                 randpadmax = (randpadmax / padbound) * padbound;
453                 n = (randpadmax - plen + extendsiz) / padbound;
454
455                 if (n > 0)
456                         n = (random() % n) * padbound;
457                 else
458                         n = 0;
459
460                 /*
461                  * make sure we do not pad too much.
462                  * MLEN limitation comes from the trailer attachment
463                  * code below.
464                  * 256 limitation comes from sequential padding.
465                  * also, the 1-octet length field in ESP trailer imposes
466                  * limitation (but is less strict than sequential padding
467                  * as length field do not count the last 2 octets).
468                  */
469                 if (extendsiz + n <= MLEN && extendsiz + n < 256)
470                         extendsiz += n;
471         }
472
473 #ifdef DIAGNOSTIC
474         if (extendsiz > MLEN || extendsiz >= 256)
475                 panic("extendsiz too big in esp_output");
476 #endif
477
478         n = m;
479         while (n->m_next)
480                 n = n->m_next;
481
482         /*
483          * if M_EXT, the external mbuf data may be shared among
484          * two consequtive TCP packets, and it may be unsafe to use the
485          * trailing space.
486          */
487         if (!(n->m_flags & M_EXT) && extendsiz < M_TRAILINGSPACE(n)) {
488                 extend = mtod(n, u_char *) + n->m_len;
489                 n->m_len += extendsiz;
490                 m->m_pkthdr.len += extendsiz;
491         } else {
492                 struct mbuf *nn;
493
494                 MGET(nn, MB_DONTWAIT, MT_DATA);
495                 if (!nn) {
496                         ipseclog((LOG_DEBUG, "esp%d_output: can't alloc mbuf",
497                             afnumber));
498                         m_freem(m);
499                         error = ENOBUFS;
500                         goto fail;
501                 }
502                 extend = mtod(nn, u_char *);
503                 nn->m_len = extendsiz;
504                 nn->m_next = NULL;
505                 n->m_next = nn;
506                 n = nn;
507                 m->m_pkthdr.len += extendsiz;
508         }
509         switch (sav->flags & SADB_X_EXT_PMASK) {
510         case SADB_X_EXT_PRAND:
511                 key_randomfill(extend, extendsiz);
512                 break;
513         case SADB_X_EXT_PZERO:
514                 bzero(extend, extendsiz);
515                 break;
516         case SADB_X_EXT_PSEQ:
517                 for (i = 0; i < extendsiz; i++)
518                         extend[i] = (i + 1) & 0xff;
519                 break;
520         }
521
522         /* initialize esp trailer. */
523         esptail = (struct esptail *)
524                 (mtod(n, u_int8_t *) + n->m_len - sizeof(struct esptail));
525         esptail->esp_nxt = nxt;
526         esptail->esp_padlen = extendsiz - 2;
527
528         /* modify IP header (for ESP header part only) */
529         switch (af) {
530 #ifdef INET
531         case AF_INET:
532                 ip = mtod(m, struct ip *);
533                 if (extendsiz < (IP_MAXPACKET - ntohs(ip->ip_len)))
534                         ip->ip_len = htons(ntohs(ip->ip_len) + extendsiz);
535                 else {
536                         ipseclog((LOG_ERR,
537                             "IPv4 ESP output: size exceeds limit\n"));
538                         ipsecstat.out_inval++;
539                         m_freem(m);
540                         error = EMSGSIZE;
541                         goto fail;
542                 }
543                 break;
544 #endif
545 #ifdef INET6
546         case AF_INET6:
547                 /* total packet length will be computed in ip6_output() */
548                 break;
549 #endif
550         }
551     }
552
553         /*
554          * pre-compute and cache intermediate key
555          */
556         error = esp_schedule(algo, sav);
557         if (error) {
558                 m_freem(m);
559                 stat->out_inval++;
560                 goto fail;
561         }
562
563         /*
564          * encrypt the packet, based on security association
565          * and the algorithm specified.
566          */
567         if (!algo->encrypt)
568                 panic("internal error: no encrypt function");
569         if ((*algo->encrypt)(m, espoff, plen + extendsiz, sav, algo, ivlen)) {
570                 /* m is already freed */
571                 ipseclog((LOG_ERR, "packet encryption failure\n"));
572                 stat->out_inval++;
573                 error = EINVAL;
574                 goto fail;
575         }
576
577         /*
578          * calculate ICV if required.
579          */
580         if (!sav->replay)
581                 goto noantireplay;
582         if (!sav->key_auth)
583                 goto noantireplay;
584         if (sav->key_auth == SADB_AALG_NONE)
585                 goto noantireplay;
586
587     {
588         const struct ah_algorithm *aalgo;
589         u_char authbuf[AH_MAXSUMSIZE];
590         struct mbuf *n;
591         u_char *p;
592         size_t siz;
593 #ifdef INET
594         struct ip *ip;
595 #endif
596
597         aalgo = ah_algorithm_lookup(sav->alg_auth);
598         if (!aalgo)
599                 goto noantireplay;
600         siz = ((aalgo->sumsiz)(sav) + 3) & ~(4 - 1);
601         if (AH_MAXSUMSIZE < siz)
602                 panic("assertion failed for AH_MAXSUMSIZE");
603
604         if (esp_auth(m, espoff, m->m_pkthdr.len - espoff, sav, authbuf)) {
605                 ipseclog((LOG_ERR, "ESP checksum generation failure\n"));
606                 m_freem(m);
607                 error = EINVAL;
608                 stat->out_inval++;
609                 goto fail;
610         }
611
612         n = m;
613         while (n->m_next)
614                 n = n->m_next;
615
616         if (!(n->m_flags & M_EXT) && siz < M_TRAILINGSPACE(n)) { /* XXX */
617                 n->m_len += siz;
618                 m->m_pkthdr.len += siz;
619                 p = mtod(n, u_char *) + n->m_len - siz;
620         } else {
621                 struct mbuf *nn;
622
623                 MGET(nn, MB_DONTWAIT, MT_DATA);
624                 if (!nn) {
625                         ipseclog((LOG_DEBUG, "can't alloc mbuf in esp%d_output",
626                             afnumber));
627                         m_freem(m);
628                         error = ENOBUFS;
629                         goto fail;
630                 }
631                 nn->m_len = siz;
632                 nn->m_next = NULL;
633                 n->m_next = nn;
634                 n = nn;
635                 m->m_pkthdr.len += siz;
636                 p = mtod(nn, u_char *);
637         }
638         bcopy(authbuf, p, siz);
639
640         /* modify IP header (for ESP header part only) */
641         switch (af) {
642 #ifdef INET
643         case AF_INET:
644                 ip = mtod(m, struct ip *);
645                 if (siz < (IP_MAXPACKET - ntohs(ip->ip_len)))
646                         ip->ip_len = htons(ntohs(ip->ip_len) + siz);
647                 else {
648                         ipseclog((LOG_ERR,
649                             "IPv4 ESP output: size exceeds limit\n"));
650                         ipsecstat.out_inval++;
651                         m_freem(m);
652                         error = EMSGSIZE;
653                         goto fail;
654                 }
655                 break;
656 #endif
657 #ifdef INET6
658         case AF_INET6:
659                 /* total packet length will be computed in ip6_output() */
660                 break;
661 #endif
662         }
663     }
664
665 noantireplay:
666         if (!m) {
667                 ipseclog((LOG_ERR,
668                     "NULL mbuf after encryption in esp%d_output", afnumber));
669         } else
670                 stat->out_success++;
671         stat->out_esphist[sav->alg_enc]++;
672         key_sa_recordxfer(sav, m);
673         return 0;
674
675 fail:
676 #if 1
677         return error;
678 #else
679         panic("something bad in esp_output");
680 #endif
681 }
682
683 #ifdef INET
684 int
685 esp4_output(struct mbuf *m, struct ipsecrequest *isr)
686 {
687         struct ip *ip;
688         if (m->m_len < sizeof(struct ip)) {
689                 ipseclog((LOG_DEBUG, "esp4_output: first mbuf too short\n"));
690                 m_freem(m);
691                 return 0;
692         }
693         ip = mtod(m, struct ip *);
694         /* XXX assumes that m->m_next points to payload */
695         return esp_output(m, &ip->ip_p, m->m_next, isr, AF_INET);
696 }
697 #endif /* INET */
698
699 #ifdef INET6
700 int
701 esp6_output(struct mbuf *m, u_char *nexthdrp, struct mbuf *md,
702             struct ipsecrequest *isr)
703 {
704         if (m->m_len < sizeof(struct ip6_hdr)) {
705                 ipseclog((LOG_DEBUG, "esp6_output: first mbuf too short\n"));
706                 m_freem(m);
707                 return 0;
708         }
709         return esp_output(m, nexthdrp, md, isr, AF_INET6);
710 }
711 #endif /* INET6 */