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