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