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

Cache object: a5f94334861dc3a397030a9a3b5af5de


[ 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.