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