The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet6/esp_core.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $FreeBSD: releng/5.2/sys/netinet6/esp_core.c 122743 2003-11-15 06:18:09Z ume $  */
    2 /*      $KAME: esp_core.c,v 1.50 2000/11/02 12:27:38 itojun 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 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/malloc.h>
   39 #include <sys/mbuf.h>
   40 #include <sys/domain.h>
   41 #include <sys/protosw.h>
   42 #include <sys/socket.h>
   43 #include <sys/errno.h>
   44 #include <sys/time.h>
   45 #include <sys/syslog.h>
   46 
   47 #include <net/if.h>
   48 #include <net/route.h>
   49 
   50 #include <netinet/in.h>
   51 #include <netinet/in_var.h>
   52 #ifdef INET6
   53 #include <netinet/ip6.h>
   54 #include <netinet6/ip6_var.h>
   55 #include <netinet/icmp6.h>
   56 #endif
   57 
   58 #include <netinet6/ipsec.h>
   59 #ifdef INET6
   60 #include <netinet6/ipsec6.h>
   61 #endif
   62 #include <netinet6/ah.h>
   63 #ifdef INET6
   64 #include <netinet6/ah6.h>
   65 #endif
   66 #include <netinet6/esp.h>
   67 #ifdef INET6
   68 #include <netinet6/esp6.h>
   69 #endif
   70 #include <netinet6/esp_rijndael.h>
   71 #include <netinet6/esp_aesctr.h>
   72 #include <net/pfkeyv2.h>
   73 #include <netkey/keydb.h>
   74 #include <netkey/key.h>
   75 
   76 #include <crypto/des/des.h>
   77 #include <crypto/blowfish/blowfish.h>
   78 #include <crypto/cast128/cast128.h>
   79 
   80 #include <net/net_osdep.h>
   81 
   82 static int esp_null_mature __P((struct secasvar *));
   83 static int esp_null_decrypt __P((struct mbuf *, size_t,
   84         struct secasvar *, const struct esp_algorithm *, int));
   85 static int esp_null_encrypt __P((struct mbuf *, size_t, size_t,
   86         struct secasvar *, const struct esp_algorithm *, int));
   87 static int esp_descbc_mature __P((struct secasvar *));
   88 static int esp_descbc_ivlen __P((const struct esp_algorithm *,
   89         struct secasvar *));
   90 static int esp_des_schedule __P((const struct esp_algorithm *,
   91         struct secasvar *));
   92 static size_t esp_des_schedlen __P((const struct esp_algorithm *));
   93 static int esp_des_blockdecrypt __P((const struct esp_algorithm *,
   94         struct secasvar *, u_int8_t *, u_int8_t *));
   95 static int esp_des_blockencrypt __P((const struct esp_algorithm *,
   96         struct secasvar *, u_int8_t *, u_int8_t *));
   97 static int esp_cbc_mature __P((struct secasvar *));
   98 static int esp_blowfish_schedule __P((const struct esp_algorithm *,
   99         struct secasvar *));
  100 static size_t esp_blowfish_schedlen __P((const struct esp_algorithm *));
  101 static int esp_blowfish_blockdecrypt __P((const struct esp_algorithm *,
  102         struct secasvar *, u_int8_t *, u_int8_t *));
  103 static int esp_blowfish_blockencrypt __P((const struct esp_algorithm *,
  104         struct secasvar *, u_int8_t *, u_int8_t *));
  105 static int esp_cast128_schedule __P((const struct esp_algorithm *,
  106         struct secasvar *));
  107 static size_t esp_cast128_schedlen __P((const struct esp_algorithm *));
  108 static int esp_cast128_blockdecrypt __P((const struct esp_algorithm *,
  109         struct secasvar *, u_int8_t *, u_int8_t *));
  110 static int esp_cast128_blockencrypt __P((const struct esp_algorithm *,
  111         struct secasvar *, u_int8_t *, u_int8_t *));
  112 static int esp_3des_schedule __P((const struct esp_algorithm *,
  113         struct secasvar *));
  114 static size_t esp_3des_schedlen __P((const struct esp_algorithm *));
  115 static int esp_3des_blockdecrypt __P((const struct esp_algorithm *,
  116         struct secasvar *, u_int8_t *, u_int8_t *));
  117 static int esp_3des_blockencrypt __P((const struct esp_algorithm *,
  118         struct secasvar *, u_int8_t *, u_int8_t *));
  119 static int esp_common_ivlen __P((const struct esp_algorithm *,
  120         struct secasvar *));
  121 static int esp_cbc_decrypt __P((struct mbuf *, size_t,
  122         struct secasvar *, const struct esp_algorithm *, int));
  123 static int esp_cbc_encrypt __P((struct mbuf *, size_t, size_t,
  124         struct secasvar *, const struct esp_algorithm *, int));
  125 
  126 #define MAXIVLEN        16
  127 
  128 static const struct esp_algorithm esp_algorithms[] = {
  129         { 8, -1, esp_descbc_mature, 64, 64, esp_des_schedlen,
  130                 "des-cbc",
  131                 esp_descbc_ivlen, esp_cbc_decrypt,
  132                 esp_cbc_encrypt, esp_des_schedule,
  133                 esp_des_blockdecrypt, esp_des_blockencrypt, },
  134         { 8, 8, esp_cbc_mature, 192, 192, esp_3des_schedlen,
  135                 "3des-cbc",
  136                 esp_common_ivlen, esp_cbc_decrypt,
  137                 esp_cbc_encrypt, esp_3des_schedule,
  138                 esp_3des_blockdecrypt, esp_3des_blockencrypt, },
  139         { 1, 0, esp_null_mature, 0, 2048, NULL, "null",
  140                 esp_common_ivlen, esp_null_decrypt,
  141                 esp_null_encrypt, NULL, },
  142         { 8, 8, esp_cbc_mature, 40, 448, esp_blowfish_schedlen, "blowfish-cbc",
  143                 esp_common_ivlen, esp_cbc_decrypt,
  144                 esp_cbc_encrypt, esp_blowfish_schedule,
  145                 esp_blowfish_blockdecrypt, esp_blowfish_blockencrypt, },
  146         { 8, 8, esp_cbc_mature, 40, 128, esp_cast128_schedlen,
  147                 "cast128-cbc",
  148                 esp_common_ivlen, esp_cbc_decrypt,
  149                 esp_cbc_encrypt, esp_cast128_schedule,
  150                 esp_cast128_blockdecrypt, esp_cast128_blockencrypt, },
  151         { 16, 16, esp_cbc_mature, 128, 256, esp_rijndael_schedlen,
  152                 "rijndael-cbc",
  153                 esp_common_ivlen, esp_cbc_decrypt,
  154                 esp_cbc_encrypt, esp_rijndael_schedule,
  155                 esp_rijndael_blockdecrypt, esp_rijndael_blockencrypt },
  156         { 16, 8, esp_aesctr_mature, 160, 288, esp_aesctr_schedlen, "aes-ctr",
  157                 esp_common_ivlen, esp_aesctr_decrypt,
  158                 esp_aesctr_encrypt, esp_aesctr_schedule },
  159 };
  160 
  161 const struct esp_algorithm *
  162 esp_algorithm_lookup(idx)
  163         int idx;
  164 {
  165 
  166         switch (idx) {
  167         case SADB_EALG_DESCBC:
  168                 return &esp_algorithms[0];
  169         case SADB_EALG_3DESCBC:
  170                 return &esp_algorithms[1];
  171         case SADB_EALG_NULL:
  172                 return &esp_algorithms[2];
  173         case SADB_X_EALG_BLOWFISHCBC:
  174                 return &esp_algorithms[3];
  175         case SADB_X_EALG_CAST128CBC:
  176                 return &esp_algorithms[4];
  177         case SADB_X_EALG_RIJNDAELCBC:
  178                 return &esp_algorithms[5];
  179         case SADB_X_EALG_AESCTR:
  180                 return &esp_algorithms[6];
  181         default:
  182                 return NULL;
  183         }
  184 }
  185 
  186 int
  187 esp_max_ivlen()
  188 {
  189         int idx;
  190         int ivlen;
  191 
  192         ivlen = 0;
  193         for (idx = 0; idx < sizeof(esp_algorithms)/sizeof(esp_algorithms[0]);
  194              idx++) {
  195                 if (esp_algorithms[idx].ivlenval > ivlen)
  196                         ivlen = esp_algorithms[idx].ivlenval;
  197         }
  198         return ivlen;
  199 }
  200 
  201 int
  202 esp_schedule(algo, sav)
  203         const struct esp_algorithm *algo;
  204         struct secasvar *sav;
  205 {
  206         int error;
  207 
  208         /* check for key length */
  209         if (_KEYBITS(sav->key_enc) < algo->keymin ||
  210             _KEYBITS(sav->key_enc) > algo->keymax) {
  211                 ipseclog((LOG_ERR,
  212                     "esp_schedule %s: unsupported key length %d: "
  213                     "needs %d to %d bits\n", algo->name, _KEYBITS(sav->key_enc),
  214                     algo->keymin, algo->keymax));
  215                 return EINVAL;
  216         }
  217 
  218         /* already allocated */
  219         if (sav->sched && sav->schedlen != 0)
  220                 return 0;
  221         /* no schedule necessary */
  222         if (!algo->schedule || !algo->schedlen)
  223                 return 0;
  224 
  225         sav->schedlen = (*algo->schedlen)(algo);
  226         sav->sched = malloc(sav->schedlen, M_SECA, M_NOWAIT);
  227         if (!sav->sched) {
  228                 sav->schedlen = 0;
  229                 return ENOBUFS;
  230         }
  231 
  232         error = (*algo->schedule)(algo, sav);
  233         if (error) {
  234                 ipseclog((LOG_ERR, "esp_schedule %s: error %d\n",
  235                     algo->name, error));
  236                 bzero(sav->sched, sav->schedlen);
  237                 free(sav->sched, M_SECA);
  238                 sav->sched = NULL;
  239                 sav->schedlen = 0;
  240         }
  241         return error;
  242 }
  243 
  244 static int
  245 esp_null_mature(sav)
  246         struct secasvar *sav;
  247 {
  248 
  249         /* anything is okay */
  250         return 0;
  251 }
  252 
  253 static int
  254 esp_null_decrypt(m, off, sav, algo, ivlen)
  255         struct mbuf *m;
  256         size_t off;             /* offset to ESP header */
  257         struct secasvar *sav;
  258         const struct esp_algorithm *algo;
  259         int ivlen;
  260 {
  261 
  262         return 0; /* do nothing */
  263 }
  264 
  265 static int
  266 esp_null_encrypt(m, off, plen, sav, algo, ivlen)
  267         struct mbuf *m;
  268         size_t off;     /* offset to ESP header */
  269         size_t plen;    /* payload length (to be encrypted) */
  270         struct secasvar *sav;
  271         const struct esp_algorithm *algo;
  272         int ivlen;
  273 {
  274 
  275         return 0; /* do nothing */
  276 }
  277 
  278 static int
  279 esp_descbc_mature(sav)
  280         struct secasvar *sav;
  281 {
  282         const struct esp_algorithm *algo;
  283 
  284         if (!(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B)) {
  285                 ipseclog((LOG_ERR, "esp_cbc_mature: "
  286                     "algorithm incompatible with 4 octets IV length\n"));
  287                 return 1;
  288         }
  289 
  290         if (!sav->key_enc) {
  291                 ipseclog((LOG_ERR, "esp_descbc_mature: no key is given.\n"));
  292                 return 1;
  293         }
  294 
  295         algo = esp_algorithm_lookup(sav->alg_enc);
  296         if (!algo) {
  297                 ipseclog((LOG_ERR,
  298                     "esp_descbc_mature: unsupported algorithm.\n"));
  299                 return 1;
  300         }
  301 
  302         if (_KEYBITS(sav->key_enc) < algo->keymin ||
  303             _KEYBITS(sav->key_enc) > algo->keymax) {
  304                 ipseclog((LOG_ERR,
  305                     "esp_descbc_mature: invalid key length %d.\n",
  306                     _KEYBITS(sav->key_enc)));
  307                 return 1;
  308         }
  309 
  310         /* weak key check */
  311         if (des_is_weak_key((des_cblock *)_KEYBUF(sav->key_enc))) {
  312                 ipseclog((LOG_ERR,
  313                     "esp_descbc_mature: weak key was passed.\n"));
  314                 return 1;
  315         }
  316 
  317         return 0;
  318 }
  319 
  320 static int
  321 esp_descbc_ivlen(algo, sav)
  322         const struct esp_algorithm *algo;
  323         struct secasvar *sav;
  324 {
  325 
  326         if (!sav)
  327                 return 8;
  328         if ((sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B))
  329                 return 4;
  330         if (!(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_DERIV))
  331                 return 4;
  332         return 8;
  333 }
  334 
  335 static size_t
  336 esp_des_schedlen(algo)
  337         const struct esp_algorithm *algo;
  338 {
  339 
  340         return sizeof(des_key_schedule);
  341 }
  342 
  343 static int
  344 esp_des_schedule(algo, sav)
  345         const struct esp_algorithm *algo;
  346         struct secasvar *sav;
  347 {
  348 
  349         if (des_key_sched((des_cblock *)_KEYBUF(sav->key_enc),
  350             *(des_key_schedule *)sav->sched))
  351                 return EINVAL;
  352         else
  353                 return 0;
  354 }
  355 
  356 static int
  357 esp_des_blockdecrypt(algo, sav, s, d)
  358         const struct esp_algorithm *algo;
  359         struct secasvar *sav;
  360         u_int8_t *s;
  361         u_int8_t *d;
  362 {
  363 
  364         /* assumption: d has a good alignment */
  365         bcopy(s, d, sizeof(DES_LONG) * 2);
  366         des_ecb_encrypt((des_cblock *)d, (des_cblock *)d,
  367             *(des_key_schedule *)sav->sched, DES_DECRYPT);
  368         return 0;
  369 }
  370 
  371 static int
  372 esp_des_blockencrypt(algo, sav, s, d)
  373         const struct esp_algorithm *algo;
  374         struct secasvar *sav;
  375         u_int8_t *s;
  376         u_int8_t *d;
  377 {
  378 
  379         /* assumption: d has a good alignment */
  380         bcopy(s, d, sizeof(DES_LONG) * 2);
  381         des_ecb_encrypt((des_cblock *)d, (des_cblock *)d,
  382             *(des_key_schedule *)sav->sched, DES_ENCRYPT);
  383         return 0;
  384 }
  385 
  386 static int
  387 esp_cbc_mature(sav)
  388         struct secasvar *sav;
  389 {
  390         int keylen;
  391         const struct esp_algorithm *algo;
  392 
  393         if (sav->flags & SADB_X_EXT_OLD) {
  394                 ipseclog((LOG_ERR,
  395                     "esp_cbc_mature: algorithm incompatible with esp-old\n"));
  396                 return 1;
  397         }
  398         if (sav->flags & SADB_X_EXT_DERIV) {
  399                 ipseclog((LOG_ERR,
  400                     "esp_cbc_mature: algorithm incompatible with derived\n"));
  401                 return 1;
  402         }
  403 
  404         if (!sav->key_enc) {
  405                 ipseclog((LOG_ERR, "esp_cbc_mature: no key is given.\n"));
  406                 return 1;
  407         }
  408 
  409         algo = esp_algorithm_lookup(sav->alg_enc);
  410         if (!algo) {
  411                 ipseclog((LOG_ERR,
  412                     "esp_cbc_mature %s: unsupported algorithm.\n", algo->name));
  413                 return 1;
  414         }
  415 
  416         keylen = sav->key_enc->sadb_key_bits;
  417         if (keylen < algo->keymin || algo->keymax < keylen) {
  418                 ipseclog((LOG_ERR,
  419                     "esp_cbc_mature %s: invalid key length %d.\n",
  420                     algo->name, sav->key_enc->sadb_key_bits));
  421                 return 1;
  422         }
  423         switch (sav->alg_enc) {
  424         case SADB_EALG_3DESCBC:
  425                 /* weak key check */
  426                 if (des_is_weak_key((des_cblock *)_KEYBUF(sav->key_enc)) ||
  427                     des_is_weak_key((des_cblock *)(_KEYBUF(sav->key_enc) + 8)) ||
  428                     des_is_weak_key((des_cblock *)(_KEYBUF(sav->key_enc) + 16))) {
  429                         ipseclog((LOG_ERR,
  430                             "esp_cbc_mature %s: weak key was passed.\n",
  431                             algo->name));
  432                         return 1;
  433                 }
  434                 break;
  435         case SADB_X_EALG_BLOWFISHCBC:
  436         case SADB_X_EALG_CAST128CBC:
  437                 break;
  438         case SADB_X_EALG_RIJNDAELCBC:
  439                 /* allows specific key sizes only */
  440                 if (!(keylen == 128 || keylen == 192 || keylen == 256)) {
  441                         ipseclog((LOG_ERR,
  442                             "esp_cbc_mature %s: invalid key length %d.\n",
  443                             algo->name, keylen));
  444                         return 1;
  445                 }
  446                 break;
  447         }
  448 
  449         return 0;
  450 }
  451 
  452 static size_t
  453 esp_blowfish_schedlen(algo)
  454         const struct esp_algorithm *algo;
  455 {
  456 
  457         return sizeof(BF_KEY);
  458 }
  459 
  460 static int
  461 esp_blowfish_schedule(algo, sav)
  462         const struct esp_algorithm *algo;
  463         struct secasvar *sav;
  464 {
  465 
  466         BF_set_key((BF_KEY *)sav->sched, _KEYLEN(sav->key_enc),
  467             _KEYBUF(sav->key_enc));
  468         return 0;
  469 }
  470 
  471 static int
  472 esp_blowfish_blockdecrypt(algo, sav, s, d)
  473         const struct esp_algorithm *algo;
  474         struct secasvar *sav;
  475         u_int8_t *s;
  476         u_int8_t *d;
  477 {
  478 
  479         BF_ecb_encrypt(s, d, (BF_KEY *)sav->sched, 0);
  480         return 0;
  481 }
  482 
  483 static int
  484 esp_blowfish_blockencrypt(algo, sav, s, d)
  485         const struct esp_algorithm *algo;
  486         struct secasvar *sav;
  487         u_int8_t *s;
  488         u_int8_t *d;
  489 {
  490 
  491         BF_ecb_encrypt(s, d, (BF_KEY *)sav->sched, 1);
  492         return 0;
  493 }
  494 
  495 static size_t
  496 esp_cast128_schedlen(algo)
  497         const struct esp_algorithm *algo;
  498 {
  499 
  500         return sizeof(cast128_key);
  501 }
  502 
  503 static int
  504 esp_cast128_schedule(algo, sav)
  505         const struct esp_algorithm *algo;
  506         struct secasvar *sav;
  507 {
  508 
  509         cast128_setkey((cast128_key *)sav->sched, _KEYBUF(sav->key_enc),
  510             _KEYLEN(sav->key_enc));
  511         return 0;
  512 }
  513 
  514 static int
  515 esp_cast128_blockdecrypt(algo, sav, s, d)
  516         const struct esp_algorithm *algo;
  517         struct secasvar *sav;
  518         u_int8_t *s;
  519         u_int8_t *d;
  520 {
  521 
  522         cast128_decrypt((cast128_key *)sav->sched, s, d);
  523         return 0;
  524 }
  525 
  526 static int
  527 esp_cast128_blockencrypt(algo, sav, s, d)
  528         const struct esp_algorithm *algo;
  529         struct secasvar *sav;
  530         u_int8_t *s;
  531         u_int8_t *d;
  532 {
  533 
  534         cast128_encrypt((cast128_key *)sav->sched, s, d);
  535         return 0;
  536 }
  537 
  538 static size_t
  539 esp_3des_schedlen(algo)
  540         const struct esp_algorithm *algo;
  541 {
  542 
  543         return sizeof(des_key_schedule) * 3;
  544 }
  545 
  546 static int
  547 esp_3des_schedule(algo, sav)
  548         const struct esp_algorithm *algo;
  549         struct secasvar *sav;
  550 {
  551         int error;
  552         des_key_schedule *p;
  553         int i;
  554         u_int8_t *k;
  555 
  556         p = (des_key_schedule *)sav->sched;
  557         k = _KEYBUF(sav->key_enc);
  558         for (i = 0; i < 3; i++) {
  559                 error = des_key_sched((des_cblock *)(k + 8 * i), p[i]);
  560                 if (error)
  561                         return EINVAL;
  562         }
  563         return 0;
  564 }
  565 
  566 static int
  567 esp_3des_blockdecrypt(algo, sav, s, d)
  568         const struct esp_algorithm *algo;
  569         struct secasvar *sav;
  570         u_int8_t *s;
  571         u_int8_t *d;
  572 {
  573         des_key_schedule *p;
  574 
  575         /* assumption: d has a good alignment */
  576         p = (des_key_schedule *)sav->sched;
  577         bcopy(s, d, sizeof(DES_LONG) * 2);
  578         des_ecb3_encrypt((des_cblock *)d, (des_cblock *)d,
  579                          p[0], p[1], p[2], DES_DECRYPT);
  580         return 0;
  581 }
  582 
  583 static int
  584 esp_3des_blockencrypt(algo, sav, s, d)
  585         const struct esp_algorithm *algo;
  586         struct secasvar *sav;
  587         u_int8_t *s;
  588         u_int8_t *d;
  589 {
  590         des_key_schedule *p;
  591 
  592         /* assumption: d has a good alignment */
  593         p = (des_key_schedule *)sav->sched;
  594         bcopy(s, d, sizeof(DES_LONG) * 2);
  595         des_ecb3_encrypt((des_cblock *)d, (des_cblock *)d,
  596                          p[0], p[1], p[2], DES_ENCRYPT);
  597         return 0;
  598 }
  599 
  600 static int
  601 esp_common_ivlen(algo, sav)
  602         const struct esp_algorithm *algo;
  603         struct secasvar *sav;
  604 {
  605 
  606         if (!algo)
  607                 panic("esp_common_ivlen: unknown algorithm");
  608         return algo->ivlenval;
  609 }
  610 
  611 static int
  612 esp_cbc_decrypt(m, off, sav, algo, ivlen)
  613         struct mbuf *m;
  614         size_t off;
  615         struct secasvar *sav;
  616         const struct esp_algorithm *algo;
  617         int ivlen;
  618 {
  619         struct mbuf *s;
  620         struct mbuf *d, *d0, *dp;
  621         int soff, doff; /* offset from the head of chain, to head of this mbuf */
  622         int sn, dn;     /* offset from the head of the mbuf, to meat */
  623         size_t ivoff, bodyoff;
  624         u_int8_t iv[MAXIVLEN], *ivp;
  625         u_int8_t sbuf[MAXIVLEN], *sp;
  626         u_int8_t *p, *q;
  627         struct mbuf *scut;
  628         int scutoff;
  629         int i;
  630         int blocklen;
  631         int derived;
  632 
  633         if (ivlen != sav->ivlen || ivlen > sizeof(iv)) {
  634                 ipseclog((LOG_ERR, "esp_cbc_decrypt %s: "
  635                     "unsupported ivlen %d\n", algo->name, ivlen));
  636                 m_freem(m);
  637                 return EINVAL;
  638         }
  639 
  640         /* assumes blocklen == padbound */
  641         blocklen = algo->padbound;
  642 
  643 #ifdef DIAGNOSTIC
  644         if (blocklen > sizeof(iv)) {
  645                 ipseclog((LOG_ERR, "esp_cbc_decrypt %s: "
  646                     "unsupported blocklen %d\n", algo->name, blocklen));
  647                 m_freem(m);
  648                 return EINVAL;
  649         }
  650 #endif
  651 
  652         if (sav->flags & SADB_X_EXT_OLD) {
  653                 /* RFC 1827 */
  654                 ivoff = off + sizeof(struct esp);
  655                 bodyoff = off + sizeof(struct esp) + ivlen;
  656                 derived = 0;
  657         } else {
  658                 /* RFC 2406 */
  659                 if (sav->flags & SADB_X_EXT_DERIV) {
  660                         /*
  661                          * draft-ietf-ipsec-ciph-des-derived-00.txt
  662                          * uses sequence number field as IV field.
  663                          */
  664                         ivoff = off + sizeof(struct esp);
  665                         bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t);
  666                         ivlen = sizeof(u_int32_t);
  667                         derived = 1;
  668                 } else {
  669                         ivoff = off + sizeof(struct newesp);
  670                         bodyoff = off + sizeof(struct newesp) + ivlen;
  671                         derived = 0;
  672                 }
  673         }
  674 
  675         /* grab iv */
  676         m_copydata(m, ivoff, ivlen, (caddr_t)iv);
  677 
  678         /* extend iv */
  679         if (ivlen == blocklen)
  680                 ;
  681         else if (ivlen == 4 && blocklen == 8) {
  682                 bcopy(&iv[0], &iv[4], 4);
  683                 iv[4] ^= 0xff;
  684                 iv[5] ^= 0xff;
  685                 iv[6] ^= 0xff;
  686                 iv[7] ^= 0xff;
  687         } else {
  688                 ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
  689                     "unsupported ivlen/blocklen: %d %d\n",
  690                     algo->name, ivlen, blocklen));
  691                 m_freem(m);
  692                 return EINVAL;
  693         }
  694 
  695         if (m->m_pkthdr.len < bodyoff) {
  696                 ipseclog((LOG_ERR, "esp_cbc_decrypt %s: bad len %d/%lu\n",
  697                     algo->name, m->m_pkthdr.len, (unsigned long)bodyoff));
  698                 m_freem(m);
  699                 return EINVAL;
  700         }
  701         if ((m->m_pkthdr.len - bodyoff) % blocklen) {
  702                 ipseclog((LOG_ERR, "esp_cbc_decrypt %s: "
  703                     "payload length must be multiple of %d\n",
  704                     algo->name, blocklen));
  705                 m_freem(m);
  706                 return EINVAL;
  707         }
  708 
  709         s = m;
  710         d = d0 = dp = NULL;
  711         soff = doff = sn = dn = 0;
  712         ivp = sp = NULL;
  713 
  714         /* skip bodyoff */
  715         while (soff < bodyoff) {
  716                 if (soff + s->m_len >= bodyoff) {
  717                         sn = bodyoff - soff;
  718                         break;
  719                 }
  720 
  721                 soff += s->m_len;
  722                 s = s->m_next;
  723         }
  724         scut = s;
  725         scutoff = sn;
  726 
  727         /* skip over empty mbuf */
  728         while (s && s->m_len == 0)
  729                 s = s->m_next;
  730 
  731         while (soff < m->m_pkthdr.len) {
  732                 /* source */
  733                 if (sn + blocklen <= s->m_len) {
  734                         /* body is continuous */
  735                         sp = mtod(s, u_int8_t *) + sn;
  736                 } else {
  737                         /* body is non-continuous */
  738                         m_copydata(s, sn, blocklen, sbuf);
  739                         sp = sbuf;
  740                 }
  741 
  742                 /* destination */
  743                 if (!d || dn + blocklen > d->m_len) {
  744                         if (d)
  745                                 dp = d;
  746                         MGET(d, M_DONTWAIT, MT_DATA);
  747                         i = m->m_pkthdr.len - (soff + sn);
  748                         if (d && i > MLEN) {
  749                                 MCLGET(d, M_DONTWAIT);
  750                                 if ((d->m_flags & M_EXT) == 0) {
  751                                         m_free(d);
  752                                         d = NULL;
  753                                 }
  754                         }
  755                         if (!d) {
  756                                 m_freem(m);
  757                                 if (d0)
  758                                         m_freem(d0);
  759                                 return ENOBUFS;
  760                         }
  761                         if (!d0)
  762                                 d0 = d;
  763                         if (dp)
  764                                 dp->m_next = d;
  765                         d->m_len = 0;
  766                         d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen;
  767                         if (d->m_len > i)
  768                                 d->m_len = i;
  769                         dn = 0;
  770                 }
  771 
  772                 /* decrypt */
  773                 (*algo->blockdecrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn);
  774 
  775                 /* xor */
  776                 p = ivp ? ivp : iv;
  777                 q = mtod(d, u_int8_t *) + dn;
  778                 for (i = 0; i < blocklen; i++)
  779                         q[i] ^= p[i];
  780 
  781                 /* next iv */
  782                 if (sp == sbuf) {
  783                         bcopy(sbuf, iv, blocklen);
  784                         ivp = NULL;
  785                 } else
  786                         ivp = sp;
  787 
  788                 sn += blocklen;
  789                 dn += blocklen;
  790 
  791                 /* find the next source block */
  792                 while (s && sn >= s->m_len) {
  793                         sn -= s->m_len;
  794                         soff += s->m_len;
  795                         s = s->m_next;
  796                 }
  797 
  798                 /* skip over empty mbuf */
  799                 while (s && s->m_len == 0)
  800                         s = s->m_next;
  801         }
  802 
  803         m_freem(scut->m_next);
  804         scut->m_len = scutoff;
  805         scut->m_next = d0;
  806 
  807         /* just in case */
  808         bzero(iv, sizeof(iv));
  809         bzero(sbuf, sizeof(sbuf));
  810 
  811         return 0;
  812 }
  813 
  814 static int
  815 esp_cbc_encrypt(m, off, plen, sav, algo, ivlen)
  816         struct mbuf *m;
  817         size_t off;
  818         size_t plen;
  819         struct secasvar *sav;
  820         const struct esp_algorithm *algo;
  821         int ivlen;
  822 {
  823         struct mbuf *s;
  824         struct mbuf *d, *d0, *dp;
  825         int soff, doff; /* offset from the head of chain, to head of this mbuf */
  826         int sn, dn;     /* offset from the head of the mbuf, to meat */
  827         size_t ivoff, bodyoff;
  828         u_int8_t iv[MAXIVLEN], *ivp;
  829         u_int8_t sbuf[MAXIVLEN], *sp;
  830         u_int8_t *p, *q;
  831         struct mbuf *scut;
  832         int scutoff;
  833         int i;
  834         int blocklen;
  835         int derived;
  836 
  837         if (ivlen != sav->ivlen || ivlen > sizeof(iv)) {
  838                 ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
  839                     "unsupported ivlen %d\n", algo->name, ivlen));
  840                 m_freem(m);
  841                 return EINVAL;
  842         }
  843 
  844         /* assumes blocklen == padbound */
  845         blocklen = algo->padbound;
  846 
  847 #ifdef DIAGNOSTIC
  848         if (blocklen > sizeof(iv)) {
  849                 ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
  850                     "unsupported blocklen %d\n", algo->name, blocklen));
  851                 m_freem(m);
  852                 return EINVAL;
  853         }
  854 #endif
  855 
  856         if (sav->flags & SADB_X_EXT_OLD) {
  857                 /* RFC 1827 */
  858                 ivoff = off + sizeof(struct esp);
  859                 bodyoff = off + sizeof(struct esp) + ivlen;
  860                 derived = 0;
  861         } else {
  862                 /* RFC 2406 */
  863                 if (sav->flags & SADB_X_EXT_DERIV) {
  864                         /*
  865                          * draft-ietf-ipsec-ciph-des-derived-00.txt
  866                          * uses sequence number field as IV field.
  867                          */
  868                         ivoff = off + sizeof(struct esp);
  869                         bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t);
  870                         ivlen = sizeof(u_int32_t);
  871                         derived = 1;
  872                 } else {
  873                         ivoff = off + sizeof(struct newesp);
  874                         bodyoff = off + sizeof(struct newesp) + ivlen;
  875                         derived = 0;
  876                 }
  877         }
  878 
  879         /* put iv into the packet.  if we are in derived mode, use seqno. */
  880         if (derived)
  881                 m_copydata(m, ivoff, ivlen, (caddr_t)iv);
  882         else {
  883                 bcopy(sav->iv, iv, ivlen);
  884                 /* maybe it is better to overwrite dest, not source */
  885                 m_copyback(m, ivoff, ivlen, (caddr_t)iv);
  886         }
  887 
  888         /* extend iv */
  889         if (ivlen == blocklen)
  890                 ;
  891         else if (ivlen == 4 && blocklen == 8) {
  892                 bcopy(&iv[0], &iv[4], 4);
  893                 iv[4] ^= 0xff;
  894                 iv[5] ^= 0xff;
  895                 iv[6] ^= 0xff;
  896                 iv[7] ^= 0xff;
  897         } else {
  898                 ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
  899                     "unsupported ivlen/blocklen: %d %d\n",
  900                     algo->name, ivlen, blocklen));
  901                 m_freem(m);
  902                 return EINVAL;
  903         }
  904 
  905         if (m->m_pkthdr.len < bodyoff) {
  906                 ipseclog((LOG_ERR, "esp_cbc_encrypt %s: bad len %d/%lu\n",
  907                     algo->name, m->m_pkthdr.len, (unsigned long)bodyoff));
  908                 m_freem(m);
  909                 return EINVAL;
  910         }
  911         if ((m->m_pkthdr.len - bodyoff) % blocklen) {
  912                 ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
  913                     "payload length must be multiple of %lu\n",
  914                     algo->name, (unsigned long)algo->padbound));
  915                 m_freem(m);
  916                 return EINVAL;
  917         }
  918 
  919         s = m;
  920         d = d0 = dp = NULL;
  921         soff = doff = sn = dn = 0;
  922         ivp = sp = NULL;
  923 
  924         /* skip bodyoff */
  925         while (soff < bodyoff) {
  926                 if (soff + s->m_len >= bodyoff) {
  927                         sn = bodyoff - soff;
  928                         break;
  929                 }
  930 
  931                 soff += s->m_len;
  932                 s = s->m_next;
  933         }
  934         scut = s;
  935         scutoff = sn;
  936 
  937         /* skip over empty mbuf */
  938         while (s && s->m_len == 0)
  939                 s = s->m_next;
  940 
  941         while (soff < m->m_pkthdr.len) {
  942                 /* source */
  943                 if (sn + blocklen <= s->m_len) {
  944                         /* body is continuous */
  945                         sp = mtod(s, u_int8_t *) + sn;
  946                 } else {
  947                         /* body is non-continuous */
  948                         m_copydata(s, sn, blocklen, (caddr_t)sbuf);
  949                         sp = sbuf;
  950                 }
  951 
  952                 /* destination */
  953                 if (!d || dn + blocklen > d->m_len) {
  954                         if (d)
  955                                 dp = d;
  956                         MGET(d, M_DONTWAIT, MT_DATA);
  957                         i = m->m_pkthdr.len - (soff + sn);
  958                         if (d && i > MLEN) {
  959                                 MCLGET(d, M_DONTWAIT);
  960                                 if ((d->m_flags & M_EXT) == 0) {
  961                                         m_free(d);
  962                                         d = NULL;
  963                                 }
  964                         }
  965                         if (!d) {
  966                                 m_freem(m);
  967                                 if (d0)
  968                                         m_freem(d0);
  969                                 return ENOBUFS;
  970                         }
  971                         if (!d0)
  972                                 d0 = d;
  973                         if (dp)
  974                                 dp->m_next = d;
  975                         d->m_len = 0;
  976                         d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen;
  977                         if (d->m_len > i)
  978                                 d->m_len = i;
  979                         dn = 0;
  980                 }
  981 
  982                 /* xor */
  983                 p = ivp ? ivp : iv;
  984                 q = sp;
  985                 for (i = 0; i < blocklen; i++)
  986                         q[i] ^= p[i];
  987 
  988                 /* encrypt */
  989                 (*algo->blockencrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn);
  990 
  991                 /* next iv */
  992                 ivp = mtod(d, u_int8_t *) + dn;
  993 
  994                 sn += blocklen;
  995                 dn += blocklen;
  996 
  997                 /* find the next source block */
  998                 while (s && sn >= s->m_len) {
  999                         sn -= s->m_len;
 1000                         soff += s->m_len;
 1001                         s = s->m_next;
 1002                 }
 1003 
 1004                 /* skip over empty mbuf */
 1005                 while (s && s->m_len == 0)
 1006                         s = s->m_next;
 1007         }
 1008 
 1009         m_freem(scut->m_next);
 1010         scut->m_len = scutoff;
 1011         scut->m_next = d0;
 1012 
 1013         /* just in case */
 1014         bzero(iv, sizeof(iv));
 1015         bzero(sbuf, sizeof(sbuf));
 1016 
 1017         key_sa_stir_iv(sav);
 1018 
 1019         return 0;
 1020 }
 1021 
 1022 /*------------------------------------------------------------*/
 1023 
 1024 /* does not free m0 on error */
 1025 int
 1026 esp_auth(m0, skip, length, sav, sum)
 1027         struct mbuf *m0;
 1028         size_t skip;    /* offset to ESP header */
 1029         size_t length;  /* payload length */
 1030         struct secasvar *sav;
 1031         u_char *sum;
 1032 {
 1033         struct mbuf *m;
 1034         size_t off;
 1035         struct ah_algorithm_state s;
 1036         u_char sumbuf[AH_MAXSUMSIZE];
 1037         const struct ah_algorithm *algo;
 1038         size_t siz;
 1039         int error;
 1040 
 1041         /* sanity checks */
 1042         if (m0->m_pkthdr.len < skip) {
 1043                 ipseclog((LOG_DEBUG, "esp_auth: mbuf length < skip\n"));
 1044                 return EINVAL;
 1045         }
 1046         if (m0->m_pkthdr.len < skip + length) {
 1047                 ipseclog((LOG_DEBUG,
 1048                     "esp_auth: mbuf length < skip + length\n"));
 1049                 return EINVAL;
 1050         }
 1051         /*
 1052          * length of esp part (excluding authentication data) must be 4n,
 1053          * since nexthdr must be at offset 4n+3.
 1054          */
 1055         if (length % 4) {
 1056                 ipseclog((LOG_ERR, "esp_auth: length is not multiple of 4\n"));
 1057                 return EINVAL;
 1058         }
 1059         if (!sav) {
 1060                 ipseclog((LOG_DEBUG, "esp_auth: NULL SA passed\n"));
 1061                 return EINVAL;
 1062         }
 1063         algo = ah_algorithm_lookup(sav->alg_auth);
 1064         if (!algo) {
 1065                 ipseclog((LOG_ERR,
 1066                     "esp_auth: bad ESP auth algorithm passed: %d\n",
 1067                     sav->alg_auth));
 1068                 return EINVAL;
 1069         }
 1070 
 1071         m = m0;
 1072         off = 0;
 1073 
 1074         siz = (((*algo->sumsiz)(sav) + 3) & ~(4 - 1));
 1075         if (sizeof(sumbuf) < siz) {
 1076                 ipseclog((LOG_DEBUG,
 1077                     "esp_auth: AH_MAXSUMSIZE is too small: siz=%lu\n",
 1078                     (u_long)siz));
 1079                 return EINVAL;
 1080         }
 1081 
 1082         /* skip the header */
 1083         while (skip) {
 1084                 if (!m)
 1085                         panic("mbuf chain?");
 1086                 if (m->m_len <= skip) {
 1087                         skip -= m->m_len;
 1088                         m = m->m_next;
 1089                         off = 0;
 1090                 } else {
 1091                         off = skip;
 1092                         skip = 0;
 1093                 }
 1094         }
 1095 
 1096         error = (*algo->init)(&s, sav);
 1097         if (error)
 1098                 return error;
 1099 
 1100         while (0 < length) {
 1101                 if (!m)
 1102                         panic("mbuf chain?");
 1103 
 1104                 if (m->m_len - off < length) {
 1105                         (*algo->update)(&s, mtod(m, u_char *) + off,
 1106                                 m->m_len - off);
 1107                         length -= m->m_len - off;
 1108                         m = m->m_next;
 1109                         off = 0;
 1110                 } else {
 1111                         (*algo->update)(&s, mtod(m, u_char *) + off, length);
 1112                         break;
 1113                 }
 1114         }
 1115         (*algo->result)(&s, sumbuf, sizeof(sumbuf));
 1116         bcopy(sumbuf, sum, siz);        /* XXX */
 1117 
 1118         return 0;
 1119 }

Cache object: 6fe0e6c07a94b717e1f4c09b1785a39f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.