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