]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet6/esp_output.c
unfinished sblive driver, playback/mixer only for now - not enabled in
[FreeBSD/FreeBSD.git] / sys / netinet6 / esp_output.c
1 /*
2  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the project nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31
32 #include "opt_inet.h"
33 #include "opt_inet6.h"
34 #include "opt_ipsec.h"
35
36 /*
37  * RFC1827/2406 Encapsulated Security Payload.
38  */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/malloc.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/kernel.h>
51 #include <sys/syslog.h>
52
53 #include <net/if.h>
54 #include <net/route.h>
55
56 #include <netinet/in.h>
57 #include <netinet/in_systm.h>
58 #include <netinet/ip.h>
59 #include <netinet/in_var.h>
60 #include <netinet/in_pcb.h>
61
62 #ifdef INET6
63 #include <netinet6/ip6.h>
64 #include <netinet6/ip6_var.h>
65 #include <netinet6/icmp6.h>
66 #endif
67
68 #include <netinet6/ipsec.h>
69 #include <netinet6/ah.h>
70 #ifdef INET6
71 #include <netinet6/ipsec6.h>
72 #include <netinet6/ah6.h>
73 #endif
74 #ifdef IPSEC_ESP
75 #include <netinet6/esp.h>
76 #ifdef INET6
77 #include <netinet6/esp6.h>
78 #endif
79 #endif
80 #include <netkey/key.h>
81 #include <netkey/keydb.h>
82 #ifdef IPSEC_DEBUG
83 #include <netkey/key_debug.h>
84 #else
85 #define KEYDEBUG(lev,arg)
86 #endif
87
88 #include <net/net_osdep.h>
89
90 static int esp_output __P((struct mbuf *, u_char *, struct mbuf *,
91         struct ipsecrequest *, int));
92
93 /*
94  * compute ESP header size.
95  */
96 size_t
97 esp_hdrsiz(isr)
98         struct ipsecrequest *isr;
99 {
100         struct secasvar *sav;
101         struct esp_algorithm *algo;
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 contrive;
117         if (sav->state != SADB_SASTATE_MATURE
118          && sav->state != SADB_SASTATE_DYING)
119                 goto contrive;
120
121         /* we need transport mode ESP. */
122         algo = &esp_algorithms[sav->alg_enc];
123         if (!algo)
124                 goto contrive;
125         ivlen = sav->ivlen;
126         if (ivlen < 0)
127                 goto contrive;
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                 if (sav->replay && sav->alg_auth && sav->key_auth)
142                         authlen = (*ah_algorithms[sav->alg_auth].sumsiz)(sav);
143                 else
144                         authlen = 0;
145                 hdrsiz = sizeof(struct newesp) + ivlen + 9 + authlen;
146         }
147
148         return hdrsiz;
149
150    contrive:
151         /*
152          * ASSUMING:
153          *      sizeof(struct newesp) > sizeof(struct esp).
154          *      8 = ivlen for CBC mode (RFC2451).
155          *      9 = (maximum padding length without random Padding length)
156          *         + (Pad Length field) + (Next Header field).
157          *      16 = maximum ICV we supported.
158          */
159         return sizeof(struct newesp) + 8 + 9 + 16;
160 }
161
162 /*
163  * Modify the packet so that the payload is encrypted.
164  * The mbuf (m) must start with IPv4 or IPv6 header.
165  * On failure, free the given mbuf and return NULL.
166  *
167  * on invocation:
168  *      m   nexthdrp md
169  *      v   v        v
170  *      IP ......... payload
171  * during the encryption:
172  *      m   nexthdrp mprev md
173  *      v   v        v     v
174  *      IP ............... esp iv payload pad padlen nxthdr
175  *                         <--><-><------><--------------->
176  *                         esplen plen    extendsiz
177  *                             ivlen
178  *                         <-----> esphlen
179  *      <-> hlen
180  *      <-----------------> espoff
181  */
182 static int
183 esp_output(m, nexthdrp, md, isr, af)
184         struct mbuf *m;
185         u_char *nexthdrp;
186         struct mbuf *md;
187         struct ipsecrequest *isr;
188         int af;
189 {
190         struct mbuf *n;
191         struct mbuf *mprev;
192         struct esp *esp;
193         struct esptail *esptail;
194         struct secasvar *sav = isr->sav;
195         struct esp_algorithm *algo;
196         u_int32_t spi;
197         u_int8_t nxt = 0;
198         size_t plen;    /*payload length to be encrypted*/
199         size_t espoff;
200         int ivlen;
201         int afnumber;
202         size_t extendsiz;
203         int error = 0;
204
205         switch (af) {
206 #ifdef INET
207         case AF_INET:
208                 afnumber = 4;
209                 break;
210 #endif
211 #ifdef INET6
212         case AF_INET6:
213                 afnumber = 6;
214                 break;
215 #endif
216         default:
217                 printf("esp_output: unsupported af %d\n", af);
218                 return 0;       /* no change at all */
219         }
220
221         /* some sanity check */
222         if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) {
223                 switch (af) {
224 #ifdef INET
225                 case AF_INET:
226                     {
227                         struct ip *ip;
228
229                         ip = mtod(m, struct ip *);
230                         printf("esp4_output: internal error: "
231                                 "sav->replay is null: "
232                                 "%x->%x, SPI=%u\n",
233                                 (u_int32_t)ntohl(ip->ip_src.s_addr),
234                                 (u_int32_t)ntohl(ip->ip_dst.s_addr),
235                                 (u_int32_t)ntohl(sav->spi));
236                         ipsecstat.out_inval++;
237                         m_freem(m);
238                         return EINVAL;
239                     }
240 #endif /*INET*/
241 #ifdef INET6
242                 case AF_INET6:
243                     {
244                         struct ip6_hdr *ip6;
245
246                         ip6 = mtod(m, struct ip6_hdr *);
247                         printf("esp6_output: internal error: "
248                                 "sav->replay is null: SPI=%u\n",
249                                 (u_int32_t)ntohl(sav->spi));
250                         ipsec6stat.out_inval++;
251                         m_freem(m);
252                         return EINVAL;
253                     }
254 #endif /*INET6*/
255                 }
256         }
257
258         algo = &esp_algorithms[sav->alg_enc];   /*XXX*/
259         spi = sav->spi;
260         ivlen = sav->ivlen;
261         /* should be okey */
262         if (ivlen < 0) {
263                 panic("invalid ivlen");
264         }
265
266     {
267         /*
268          * insert ESP header.
269          * XXX inserts ESP header right after IPv4 header.  should
270          * chase the header chain.
271          * XXX sequential number
272          */
273 #ifdef INET
274         struct ip *ip = NULL;
275 #endif
276 #ifdef INET6
277         struct ip6_hdr *ip6 = NULL;
278 #endif
279         size_t esplen;  /*sizeof(struct esp/newesp)*/
280         size_t esphlen; /*sizeof(struct esp/newesp) + ivlen*/
281         size_t hlen = 0;        /*ip header len*/
282
283         if (sav->flags & SADB_X_EXT_OLD) {
284                 /* RFC 1827 */
285                 esplen = sizeof(struct esp);
286         } else {
287                 /* RFC 2406 */
288                 if (sav->flags & SADB_X_EXT_DERIV)
289                         esplen = sizeof(struct esp);
290                 else
291                         esplen = sizeof(struct newesp);
292         }
293         esphlen = esplen + ivlen;
294
295         for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
296                 ;
297         if (mprev == NULL || mprev->m_next != md) {
298                 printf("esp%d_output: md is not in chain\n", 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) {
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                         printf("IPv4 ESP output: size exceeds limit\n");
370                         ipsecstat.out_inval++;
371                         m_freem(m);
372                         error = EMSGSIZE;
373                         goto fail;
374                 }
375                 break;
376 #endif
377 #ifdef INET6
378         case AF_INET6:
379                 /* total packet length will be computed in ip6_output() */
380                 break;
381 #endif
382         }
383     }
384
385         /* initialize esp header. */
386         esp->esp_spi = spi;
387         if ((sav->flags & SADB_X_EXT_OLD) == 0) {
388                 struct newesp *nesp;
389                 nesp = (struct newesp *)esp;
390                 sav->replay->count++;
391                 /*
392                  * XXX sequence number must not be cycled, if the SA is
393                  * installed by IKE daemon.
394                  */
395                 nesp->esp_seq = htonl(sav->replay->count);
396         }
397
398     {
399         /*
400          * find the last mbuf. make some room for ESP trailer.
401          * XXX new-esp authentication data
402          */
403 #ifdef INET
404         struct ip *ip = NULL;
405 #endif
406         size_t padbound;
407
408         if (algo->padbound)
409                 padbound = algo->padbound;
410         else
411                 padbound = 4;
412         /* ESP packet, including nxthdr field, must be length of 4n */
413         if (padbound < 4)
414                 padbound = 4;
415
416         extendsiz = padbound - (plen % padbound);
417         if (extendsiz == 1)
418                 extendsiz = padbound + 1;
419
420         n = m;
421         while (n->m_next)
422                 n = n->m_next;
423
424         /*
425          * if M_EXT, the external part may be shared among
426          * two consequtive TCP packets.
427          */
428         if (!(n->m_flags & M_EXT) && extendsiz < M_TRAILINGSPACE(n)) {
429                 switch (sav->flags & SADB_X_EXT_PMASK) {
430                 case SADB_X_EXT_PRAND:
431                         break;
432                 case SADB_X_EXT_PZERO:
433                         bzero((caddr_t)(mtod(n, u_int8_t *) + n->m_len),
434                                 extendsiz);
435                         break;
436                 case SADB_X_EXT_PSEQ:
437                     {
438                         int i;
439                         u_char *p;
440                         p = mtod(n, u_char *) + n->m_len;
441                         for (i = 0; i < extendsiz; i++)
442                                 p[i] = i + 1;
443                         break;
444                     }
445                 }
446                 n->m_len += extendsiz;
447                 m->m_pkthdr.len += extendsiz;
448         } else {
449                 struct mbuf *nn;
450
451                 MGET(nn, M_DONTWAIT, MT_DATA);
452                 if (!nn) {
453                         printf("esp%d_output: can't alloc mbuf", afnumber);
454                         m_freem(m);
455                         error = ENOBUFS;
456                         goto fail;
457                 }
458                 nn->m_len = extendsiz;
459                 switch (sav->flags & SADB_X_EXT_PMASK) {
460                 case SADB_X_EXT_PRAND:
461                         break;
462                 case SADB_X_EXT_PZERO:
463                         bzero(mtod(nn, caddr_t), extendsiz);
464                         break;
465                 case SADB_X_EXT_PSEQ:
466                     {
467                         int i;
468                         u_char *p;
469                         p = mtod(nn, u_char *);
470                         for (i = 0; i < extendsiz; i++)
471                                 p[i] = i + 1;
472                         break;
473                     }
474                 }
475                 nn->m_next = NULL;
476                 n->m_next = nn;
477                 n = nn;
478                 m->m_pkthdr.len += extendsiz;
479         }
480
481         /* initialize esp trailer. */
482         esptail = (struct esptail *)
483                 (mtod(n, u_int8_t *) + n->m_len - sizeof(struct esptail));
484         esptail->esp_nxt = nxt;
485         esptail->esp_padlen = extendsiz - 2;
486
487         /* modify IP header (for ESP header part only) */
488         switch (af) {
489 #ifdef INET
490         case AF_INET:
491                 ip = mtod(m, struct ip *);
492                 if (extendsiz < (IP_MAXPACKET - ntohs(ip->ip_len)))
493                         ip->ip_len = htons(ntohs(ip->ip_len) + extendsiz);
494                 else {
495                         printf("IPv4 ESP output: size exceeds limit\n");
496                         ipsecstat.out_inval++;
497                         m_freem(m);
498                         error = EMSGSIZE;
499                         goto fail;
500                 }
501                 break;
502 #endif
503 #ifdef INET6
504         case AF_INET6:
505                 /* total packet length will be computed in ip6_output() */
506                 break;
507 #endif
508         }
509     }
510
511         /*
512          * encrypt the packet, based on security association
513          * and the algorithm specified.
514          */
515         if (!algo->encrypt)
516                 panic("internal error: no encrypt function");
517         if ((*algo->encrypt)(m, espoff, plen + extendsiz, sav, algo, ivlen)) {
518                 printf("packet encryption failure\n");
519                 m_freem(m);
520                 switch (af) {
521 #ifdef INET
522                 case AF_INET:
523                         ipsecstat.out_inval++;
524                         break;
525 #endif
526 #ifdef INET6
527                 case AF_INET6:
528                         ipsec6stat.out_inval++;
529                         break;
530 #endif
531                 }
532                 error = EINVAL;
533                 goto fail;
534         }
535
536         /*
537          * calculate ICV if required.
538          */
539         if (!sav->replay)
540                 goto noantireplay;
541         if (!sav->key_auth)
542                 goto noantireplay;
543         if (!sav->alg_auth)
544                 goto noantireplay;
545     {
546         u_char authbuf[AH_MAXSUMSIZE];
547         struct mbuf *n;
548         u_char *p;
549         size_t siz;
550         struct ip *ip;
551
552         siz = (((*ah_algorithms[sav->alg_auth].sumsiz)(sav) + 3) & ~(4 - 1));
553         if (AH_MAXSUMSIZE < siz)
554                 panic("assertion failed for AH_MAXSUMSIZE");
555
556         if (esp_auth(m, espoff, m->m_pkthdr.len - espoff, sav, authbuf))
557                 goto noantireplay;
558
559         n = m;
560         while (n->m_next)
561                 n = n->m_next;
562
563         if (!(n->m_flags & M_EXT) && siz < M_TRAILINGSPACE(n)) {        /*XXX*/
564                 n->m_len += siz;
565                 m->m_pkthdr.len += siz;
566                 p = mtod(n, u_char *) + n->m_len - siz;
567         } else {
568                 struct mbuf *nn;
569
570                 MGET(nn, M_DONTWAIT, MT_DATA);
571                 if (!nn) {
572                         printf("can't alloc mbuf in esp%d_output", afnumber);
573                         m_freem(m);
574                         error = ENOBUFS;
575                         goto fail;
576                 }
577                 nn->m_len = siz;
578                 nn->m_next = NULL;
579                 n->m_next = nn;
580                 n = nn;
581                 m->m_pkthdr.len += siz;
582                 p = mtod(nn, u_char *);
583         }
584         bcopy(authbuf, p, siz);
585
586         /* modify IP header (for ESP header part only) */
587         switch (af) {
588 #ifdef INET
589         case AF_INET:
590                 ip = mtod(m, struct ip *);
591                 if (siz < (IP_MAXPACKET - ntohs(ip->ip_len)))
592                         ip->ip_len = htons(ntohs(ip->ip_len) + siz);
593                 else {
594                         printf("IPv4 ESP output: size exceeds limit\n");
595                         ipsecstat.out_inval++;
596                         m_freem(m);
597                         error = EMSGSIZE;
598                         goto fail;
599                 }
600                 break;
601 #endif
602 #ifdef INET6
603         case AF_INET6:
604                 /* total packet length will be computed in ip6_output() */
605                 break;
606 #endif
607         }
608     }
609
610 noantireplay:
611         if (!m)
612                 printf("NULL mbuf after encryption in esp%d_output", afnumber);
613         else {
614                 switch (af) {
615 #ifdef INET
616                 case AF_INET:
617                         ipsecstat.out_success++;
618                         break;
619 #endif
620 #ifdef INET6
621                 case AF_INET6:
622                         ipsec6stat.out_success++;
623                         break;
624 #endif
625                 }
626         }
627         switch (af) {
628 #ifdef INET
629         case AF_INET:
630                 ipsecstat.out_esphist[sav->alg_enc]++;
631                 break;
632 #endif
633 #ifdef INET6
634         case AF_INET6:
635                 ipsec6stat.out_esphist[sav->alg_enc]++;
636                 break;
637 #endif
638         }
639         key_sa_recordxfer(sav, m);
640         return 0;
641
642 fail:
643 #if 1
644         return error;
645 #else
646         panic("something bad in esp_output");
647 #endif
648 }
649
650 #ifdef INET
651 int
652 esp4_output(m, isr)
653         struct mbuf *m;
654         struct ipsecrequest *isr;
655 {
656         struct ip *ip;
657         if (m->m_len < sizeof(struct ip)) {
658                 printf("esp4_output: first mbuf too short\n");
659                 m_freem(m);
660                 return NULL;
661         }
662         ip = mtod(m, struct ip *);
663         /* XXX assumes that m->m_next points to payload */
664         return esp_output(m, &ip->ip_p, m->m_next, isr, AF_INET);
665 }
666 #endif /*INET*/
667
668 #ifdef INET6
669 int
670 esp6_output(m, nexthdrp, md, isr)
671         struct mbuf *m;
672         u_char *nexthdrp;
673         struct mbuf *md;
674         struct ipsecrequest *isr;
675 {
676         if (m->m_len < sizeof(struct ip6_hdr)) {
677                 printf("esp6_output: first mbuf too short\n");
678                 m_freem(m);
679                 return NULL;
680         }
681         return esp_output(m, nexthdrp, md, isr, AF_INET6);
682 }
683 #endif /*INET6*/