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/netgraph/ng_mppc.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 /*
    2  * ng_mppc.c
    3  */
    4 
    5 /*-
    6  * Copyright (c) 1996-2000 Whistle Communications, Inc.
    7  * All rights reserved.
    8  * 
    9  * Subject to the following obligations and disclaimer of warranty, use and
   10  * redistribution of this software, in source or object code forms, with or
   11  * without modifications are expressly permitted by Whistle Communications;
   12  * provided, however, that:
   13  * 1. Any and all reproductions of the source or object code must include the
   14  *    copyright notice above and the following disclaimer of warranties; and
   15  * 2. No rights are granted, in any manner or form, to use Whistle
   16  *    Communications, Inc. trademarks, including the mark "WHISTLE
   17  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
   18  *    such appears in the above copyright notice or in the software.
   19  * 
   20  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
   21  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
   22  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
   23  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
   24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
   25  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
   26  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
   27  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
   28  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
   29  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
   30  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
   31  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
   32  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
   33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   35  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
   36  * OF SUCH DAMAGE.
   37  *
   38  * Author: Archie Cobbs <archie@freebsd.org>
   39  *
   40  * $Whistle: ng_mppc.c,v 1.4 1999/11/25 00:10:12 archie Exp $
   41  * $FreeBSD$
   42  */
   43 
   44 /*
   45  * Microsoft PPP compression (MPPC) and encryption (MPPE) netgraph node type.
   46  *
   47  * You must define one or both of the NETGRAPH_MPPC_COMPRESSION and/or
   48  * NETGRAPH_MPPC_ENCRYPTION options for this node type to be useful.
   49  */
   50 
   51 #include <sys/param.h>
   52 #include <sys/systm.h>
   53 #include <sys/kernel.h>
   54 #include <sys/mbuf.h>
   55 #include <sys/malloc.h>
   56 #include <sys/errno.h>
   57 #include <sys/syslog.h>
   58 
   59 #include <netgraph/ng_message.h>
   60 #include <netgraph/netgraph.h>
   61 #include <netgraph/ng_mppc.h>
   62 
   63 #include "opt_netgraph.h"
   64 
   65 #if !defined(NETGRAPH_MPPC_COMPRESSION) && !defined(NETGRAPH_MPPC_ENCRYPTION)
   66 #ifdef KLD_MODULE
   67 /* XXX NETGRAPH_MPPC_COMPRESSION isn't functional yet */
   68 #define NETGRAPH_MPPC_ENCRYPTION
   69 #else
   70 /* This case is indicative of an error in sys/conf files */
   71 #error Need either NETGRAPH_MPPC_COMPRESSION or NETGRAPH_MPPC_ENCRYPTION
   72 #endif
   73 #endif
   74 
   75 #ifdef NG_SEPARATE_MALLOC
   76 MALLOC_DEFINE(M_NETGRAPH_MPPC, "netgraph_mppc", "netgraph mppc node ");
   77 #else
   78 #define M_NETGRAPH_MPPC M_NETGRAPH
   79 #endif
   80 
   81 #ifdef NETGRAPH_MPPC_COMPRESSION
   82 /* XXX this file doesn't exist yet, but hopefully someday it will... */
   83 #include <net/mppc.h>
   84 #endif
   85 #ifdef NETGRAPH_MPPC_ENCRYPTION
   86 #include <crypto/rc4/rc4.h>
   87 #endif
   88 #include <crypto/sha1.h>
   89 
   90 /* Decompression blowup */
   91 #define MPPC_DECOMP_BUFSIZE     8092            /* allocate buffer this big */
   92 #define MPPC_DECOMP_SAFETY      100             /*   plus this much margin */
   93 
   94 /* MPPC/MPPE header length */
   95 #define MPPC_HDRLEN             2
   96 
   97 /* Key length */
   98 #define KEYLEN(b)               (((b) & MPPE_128) ? 16 : 8)
   99 
  100 /*
  101  * When packets are lost with MPPE, we may have to re-key arbitrarily
  102  * many times to 'catch up' to the new jumped-ahead sequence number.
  103  * Since this can be expensive, we pose a limit on how many re-keyings
  104  * we will do at one time to avoid a possible D.O.S. vulnerability.
  105  * This should instead be a configurable parameter.
  106  */
  107 #define MPPE_MAX_REKEY          1000
  108 
  109 /* MPPC packet header bits */
  110 #define MPPC_FLAG_FLUSHED       0x8000          /* xmitter reset state */
  111 #define MPPC_FLAG_RESTART       0x4000          /* compress history restart */
  112 #define MPPC_FLAG_COMPRESSED    0x2000          /* packet is compresed */
  113 #define MPPC_FLAG_ENCRYPTED     0x1000          /* packet is encrypted */
  114 #define MPPC_CCOUNT_MASK        0x0fff          /* sequence number mask */
  115 
  116 #define MPPC_CCOUNT_INC(d)      ((d) = (((d) + 1) & MPPC_CCOUNT_MASK))
  117 
  118 #define MPPE_UPDATE_MASK        0xff            /* coherency count when we're */
  119 #define MPPE_UPDATE_FLAG        0xff            /*   supposed to update key */
  120 
  121 #define MPPC_COMP_OK            0x05
  122 #define MPPC_DECOMP_OK          0x05
  123 
  124 /* Per direction info */
  125 struct ng_mppc_dir {
  126         struct ng_mppc_config   cfg;            /* configuration */
  127         hook_p                  hook;           /* netgraph hook */
  128         u_int16_t               cc:12;          /* coherency count */
  129         u_char                  flushed;        /* clean history (xmit only) */
  130 #ifdef NETGRAPH_MPPC_COMPRESSION
  131         u_char                  *history;       /* compression history */
  132 #endif
  133 #ifdef NETGRAPH_MPPC_ENCRYPTION
  134         u_char                  key[MPPE_KEY_LEN];      /* session key */
  135         struct rc4_state        rc4;                    /* rc4 state */
  136 #endif
  137 };
  138 
  139 /* Node private data */
  140 struct ng_mppc_private {
  141         struct ng_mppc_dir      xmit;           /* compress/encrypt config */
  142         struct ng_mppc_dir      recv;           /* decompress/decrypt config */
  143         ng_ID_t                 ctrlnode;       /* path to controlling node */
  144 };
  145 typedef struct ng_mppc_private *priv_p;
  146 
  147 /* Netgraph node methods */
  148 static ng_constructor_t ng_mppc_constructor;
  149 static ng_rcvmsg_t      ng_mppc_rcvmsg;
  150 static ng_shutdown_t    ng_mppc_shutdown;
  151 static ng_newhook_t     ng_mppc_newhook;
  152 static ng_rcvdata_t     ng_mppc_rcvdata;
  153 static ng_disconnect_t  ng_mppc_disconnect;
  154 
  155 /* Helper functions */
  156 static int      ng_mppc_compress(node_p node,
  157                         struct mbuf **datap);
  158 static int      ng_mppc_decompress(node_p node,
  159                         struct mbuf **datap);
  160 #ifdef NETGRAPH_MPPC_ENCRYPTION
  161 static void     ng_mppc_getkey(const u_char *h, u_char *h2, int len);
  162 static void     ng_mppc_updatekey(u_int32_t bits,
  163                         u_char *key0, u_char *key, struct rc4_state *rc4);
  164 #endif
  165 static void     ng_mppc_reset_req(node_p node);
  166 
  167 /* Node type descriptor */
  168 static struct ng_type ng_mppc_typestruct = {
  169         .version =      NG_ABI_VERSION,
  170         .name =         NG_MPPC_NODE_TYPE,
  171         .constructor =  ng_mppc_constructor,
  172         .rcvmsg =       ng_mppc_rcvmsg,
  173         .shutdown =     ng_mppc_shutdown,
  174         .newhook =      ng_mppc_newhook,
  175         .rcvdata =      ng_mppc_rcvdata,
  176         .disconnect =   ng_mppc_disconnect,
  177 };
  178 NETGRAPH_INIT(mppc, &ng_mppc_typestruct);
  179 
  180 #ifdef NETGRAPH_MPPC_ENCRYPTION
  181 /* Depend on separate rc4 module */
  182 MODULE_DEPEND(ng_mppc, rc4, 1, 1, 1);
  183 #endif
  184 
  185 /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */
  186 static const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e };
  187 
  188 #define ERROUT(x)       do { error = (x); goto done; } while (0)
  189 
  190 /************************************************************************
  191                         NETGRAPH NODE STUFF
  192  ************************************************************************/
  193 
  194 /*
  195  * Node type constructor
  196  */
  197 static int
  198 ng_mppc_constructor(node_p node)
  199 {
  200         priv_p priv;
  201 
  202         /* Allocate private structure */
  203         MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH_MPPC, M_NOWAIT | M_ZERO);
  204         if (priv == NULL)
  205                 return (ENOMEM);
  206 
  207         NG_NODE_SET_PRIVATE(node, priv);
  208 
  209         /* This node is not thread safe. */
  210         NG_NODE_FORCE_WRITER(node);
  211 
  212         /* Done */
  213         return (0);
  214 }
  215 
  216 /*
  217  * Give our OK for a hook to be added
  218  */
  219 static int
  220 ng_mppc_newhook(node_p node, hook_p hook, const char *name)
  221 {
  222         const priv_p priv = NG_NODE_PRIVATE(node);
  223         hook_p *hookPtr;
  224 
  225         /* Check hook name */
  226         if (strcmp(name, NG_MPPC_HOOK_COMP) == 0)
  227                 hookPtr = &priv->xmit.hook;
  228         else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0)
  229                 hookPtr = &priv->recv.hook;
  230         else
  231                 return (EINVAL);
  232 
  233         /* See if already connected */
  234         if (*hookPtr != NULL)
  235                 return (EISCONN);
  236 
  237         /* OK */
  238         *hookPtr = hook;
  239         return (0);
  240 }
  241 
  242 /*
  243  * Receive a control message
  244  */
  245 static int
  246 ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook)
  247 {
  248         const priv_p priv = NG_NODE_PRIVATE(node);
  249         struct ng_mesg *resp = NULL;
  250         int error = 0;
  251         struct ng_mesg *msg;
  252 
  253         NGI_GET_MSG(item, msg);
  254         switch (msg->header.typecookie) {
  255         case NGM_MPPC_COOKIE:
  256                 switch (msg->header.cmd) {
  257                 case NGM_MPPC_CONFIG_COMP:
  258                 case NGM_MPPC_CONFIG_DECOMP:
  259                     {
  260                         struct ng_mppc_config *const cfg
  261                             = (struct ng_mppc_config *)msg->data;
  262                         const int isComp =
  263                             msg->header.cmd == NGM_MPPC_CONFIG_COMP;
  264                         struct ng_mppc_dir *const d = isComp ?
  265                             &priv->xmit : &priv->recv;
  266 
  267                         /* Check configuration */
  268                         if (msg->header.arglen != sizeof(*cfg))
  269                                 ERROUT(EINVAL);
  270                         if (cfg->enable) {
  271                                 if ((cfg->bits & ~MPPC_VALID_BITS) != 0)
  272                                         ERROUT(EINVAL);
  273 #ifndef NETGRAPH_MPPC_COMPRESSION
  274                                 if ((cfg->bits & MPPC_BIT) != 0)
  275                                         ERROUT(EPROTONOSUPPORT);
  276 #endif
  277 #ifndef NETGRAPH_MPPC_ENCRYPTION
  278                                 if ((cfg->bits & MPPE_BITS) != 0)
  279                                         ERROUT(EPROTONOSUPPORT);
  280 #endif
  281                         } else
  282                                 cfg->bits = 0;
  283 
  284                         /* Save return address so we can send reset-req's */
  285                         if (!isComp)
  286                                 priv->ctrlnode = NGI_RETADDR(item);
  287 
  288                         /* Configuration is OK, reset to it */
  289                         d->cfg = *cfg;
  290 
  291 #ifdef NETGRAPH_MPPC_COMPRESSION
  292                         /* Initialize state buffers for compression */
  293                         if (d->history != NULL) {
  294                                 FREE(d->history, M_NETGRAPH_MPPC);
  295                                 d->history = NULL;
  296                         }
  297                         if ((cfg->bits & MPPC_BIT) != 0) {
  298                                 MALLOC(d->history, u_char *,
  299                                     isComp ? MPPC_SizeOfCompressionHistory() :
  300                                     MPPC_SizeOfDecompressionHistory(),
  301                                     M_NETGRAPH_MPPC, M_NOWAIT);
  302                                 if (d->history == NULL)
  303                                         ERROUT(ENOMEM);
  304                                 if (isComp)
  305                                         MPPC_InitCompressionHistory(d->history);
  306                                 else {
  307                                         MPPC_InitDecompressionHistory(
  308                                             d->history);
  309                                 }
  310                         }
  311 #endif
  312 
  313 #ifdef NETGRAPH_MPPC_ENCRYPTION
  314                         /* Generate initial session keys for encryption */
  315                         if ((cfg->bits & MPPE_BITS) != 0) {
  316                                 const int keylen = KEYLEN(cfg->bits);
  317 
  318                                 bcopy(cfg->startkey, d->key, keylen);
  319                                 ng_mppc_getkey(cfg->startkey, d->key, keylen);
  320                                 if ((cfg->bits & MPPE_40) != 0)
  321                                         bcopy(&ng_mppe_weakenkey, d->key, 3);
  322                                 else if ((cfg->bits & MPPE_56) != 0)
  323                                         bcopy(&ng_mppe_weakenkey, d->key, 1);
  324                                 rc4_init(&d->rc4, d->key, keylen);
  325                         }
  326 #endif
  327 
  328                         /* Initialize other state */
  329                         d->cc = 0;
  330                         d->flushed = 0;
  331                         break;
  332                     }
  333 
  334                 case NGM_MPPC_RESETREQ:
  335                         ng_mppc_reset_req(node);
  336                         break;
  337 
  338                 default:
  339                         error = EINVAL;
  340                         break;
  341                 }
  342                 break;
  343         default:
  344                 error = EINVAL;
  345                 break;
  346         }
  347 done:
  348         NG_RESPOND_MSG(error, node, item, resp);
  349         NG_FREE_MSG(msg);
  350         return (error);
  351 }
  352 
  353 /*
  354  * Receive incoming data on our hook.
  355  */
  356 static int
  357 ng_mppc_rcvdata(hook_p hook, item_p item)
  358 {
  359         const node_p node = NG_HOOK_NODE(hook);
  360         const priv_p priv = NG_NODE_PRIVATE(node);
  361         int error;
  362         struct mbuf *m;
  363 
  364         NGI_GET_M(item, m);
  365         /* Compress and/or encrypt */
  366         if (hook == priv->xmit.hook) {
  367                 if (!priv->xmit.cfg.enable) {
  368                         NG_FREE_M(m);
  369                         NG_FREE_ITEM(item);
  370                         return (ENXIO);
  371                 }
  372                 if ((error = ng_mppc_compress(node, &m)) != 0) {
  373                         NG_FREE_ITEM(item);
  374                         return(error);
  375                 }
  376                 NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m);
  377                 return (error);
  378         }
  379 
  380         /* Decompress and/or decrypt */
  381         if (hook == priv->recv.hook) {
  382                 if (!priv->recv.cfg.enable) {
  383                         NG_FREE_M(m);
  384                         NG_FREE_ITEM(item);
  385                         return (ENXIO);
  386                 }
  387                 if ((error = ng_mppc_decompress(node, &m)) != 0) {
  388                         NG_FREE_ITEM(item);
  389                         if (error == EINVAL && priv->ctrlnode != 0) {
  390                                 struct ng_mesg *msg;
  391 
  392                                 /* Need to send a reset-request */
  393                                 NG_MKMESSAGE(msg, NGM_MPPC_COOKIE,
  394                                     NGM_MPPC_RESETREQ, 0, M_NOWAIT);
  395                                 if (msg == NULL)
  396                                         return (error);
  397                                 NG_SEND_MSG_ID(error, node, msg,
  398                                         priv->ctrlnode, 0); 
  399                         }
  400                         return (error);
  401                 }
  402                 NG_FWD_NEW_DATA(error, item, priv->recv.hook, m);
  403                 return (error);
  404         }
  405 
  406         /* Oops */
  407         panic("%s: unknown hook", __func__);
  408 #ifdef RESTARTABLE_PANICS
  409         return (EINVAL);
  410 #endif
  411 }
  412 
  413 /*
  414  * Destroy node
  415  */
  416 static int
  417 ng_mppc_shutdown(node_p node)
  418 {
  419         const priv_p priv = NG_NODE_PRIVATE(node);
  420 
  421         /* Take down netgraph node */
  422 #ifdef NETGRAPH_MPPC_COMPRESSION
  423         if (priv->xmit.history != NULL)
  424                 FREE(priv->xmit.history, M_NETGRAPH_MPPC);
  425         if (priv->recv.history != NULL)
  426                 FREE(priv->recv.history, M_NETGRAPH_MPPC);
  427 #endif
  428         bzero(priv, sizeof(*priv));
  429         FREE(priv, M_NETGRAPH_MPPC);
  430         NG_NODE_SET_PRIVATE(node, NULL);
  431         NG_NODE_UNREF(node);            /* let the node escape */
  432         return (0);
  433 }
  434 
  435 /*
  436  * Hook disconnection
  437  */
  438 static int
  439 ng_mppc_disconnect(hook_p hook)
  440 {
  441         const node_p node = NG_HOOK_NODE(hook);
  442         const priv_p priv = NG_NODE_PRIVATE(node);
  443 
  444         /* Zero out hook pointer */
  445         if (hook == priv->xmit.hook)
  446                 priv->xmit.hook = NULL;
  447         if (hook == priv->recv.hook)
  448                 priv->recv.hook = NULL;
  449 
  450         /* Go away if no longer connected */
  451         if ((NG_NODE_NUMHOOKS(node) == 0)
  452         && NG_NODE_IS_VALID(node))
  453                 ng_rmnode_self(node);
  454         return (0);
  455 }
  456 
  457 /************************************************************************
  458                         HELPER STUFF
  459  ************************************************************************/
  460 
  461 /*
  462  * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
  463  * The original mbuf is not free'd.
  464  */
  465 static int
  466 ng_mppc_compress(node_p node, struct mbuf **datap)
  467 {
  468         const priv_p priv = NG_NODE_PRIVATE(node);
  469         struct ng_mppc_dir *const d = &priv->xmit;
  470         u_int16_t header;
  471         struct mbuf *m = *datap;
  472 
  473         /* Initialize */
  474         header = d->cc;
  475 
  476         /* Always set the flushed bit in stateless mode */
  477         if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) {
  478                 header |= MPPC_FLAG_FLUSHED;
  479                 d->flushed = 0;
  480         }
  481 
  482         /* Compress packet (if compression enabled) */
  483 #ifdef NETGRAPH_MPPC_COMPRESSION
  484         if ((d->cfg.bits & MPPC_BIT) != 0) {
  485                 u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS;
  486                 u_char *inbuf, *outbuf;
  487                 int outlen, inlen;
  488                 u_char *source, *dest;
  489                 u_long sourceCnt, destCnt;
  490                 int rtn;
  491 
  492                 /* Work with contiguous regions of memory. */
  493                 inlen = m->m_pkthdr.len;
  494                 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
  495                 if (inbuf == NULL) {
  496                         m_freem(m);
  497                         return (ENOMEM);
  498                 }
  499                 m_copydata(m, 0, inlen, (caddr_t)inbuf);
  500 
  501                 outlen = MPPC_MAX_BLOWUP(inlen);
  502                 outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT);
  503                 if (outbuf == NULL) {
  504                         m_freem(m);
  505                         free(inbuf, M_NETGRAPH_MPPC);
  506                         return (ENOMEM);
  507                 }
  508 
  509                 /* Prepare to compress */
  510                 source = inbuf;
  511                 sourceCnt = inlen;
  512                 dest = outbuf;
  513                 destCnt = outlen;
  514                 if ((d->cfg.bits & MPPE_STATELESS) == 0)
  515                         flags |= MPPC_SAVE_HISTORY;
  516 
  517                 /* Compress */
  518                 rtn = MPPC_Compress(&source, &dest, &sourceCnt,
  519                         &destCnt, d->history, flags, 0);
  520 
  521                 /* Check return value */
  522                 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
  523                 if ((rtn & MPPC_EXPANDED) == 0
  524                     && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) {
  525                         outlen -= destCnt;     
  526                         header |= MPPC_FLAG_COMPRESSED;
  527                         if ((rtn & MPPC_RESTART_HISTORY) != 0)
  528                                 header |= MPPC_FLAG_RESTART;  
  529                                 
  530                         /* Replace m by the compresed one. */
  531                         m_freem(m);
  532                         m = m_devget((caddr_t)outbuf, outlen, 0, NULL, NULL);
  533                 }
  534                 d->flushed = (rtn & MPPC_EXPANDED) != 0
  535                     || (flags & MPPC_SAVE_HISTORY) == 0;
  536 
  537                 free(inbuf, M_NETGRAPH_MPPC);
  538                 free(outbuf, M_NETGRAPH_MPPC);
  539 
  540                 /* Check m_devget() result. */
  541                 if (m == NULL)
  542                         return (ENOMEM);
  543         }
  544 #endif
  545 
  546         /* Now encrypt packet (if encryption enabled) */
  547 #ifdef NETGRAPH_MPPC_ENCRYPTION
  548         if ((d->cfg.bits & MPPE_BITS) != 0) {
  549                 struct mbuf *m1;
  550 
  551                 /* Set header bits */
  552                 header |= MPPC_FLAG_ENCRYPTED;
  553 
  554                 /* Update key if it's time */
  555                 if ((d->cfg.bits & MPPE_STATELESS) != 0
  556                     || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
  557                         ng_mppc_updatekey(d->cfg.bits,
  558                             d->cfg.startkey, d->key, &d->rc4);
  559                 } else if ((header & MPPC_FLAG_FLUSHED) != 0) {
  560                         /* Need to reset key if we say we did 
  561                            and ng_mppc_updatekey wasn't called to do it also. */
  562                         rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
  563                 }
  564 
  565                 /* We must own the mbuf chain exclusively to modify it. */
  566                 m = m_unshare(m, M_DONTWAIT);
  567                 if (m == NULL)
  568                         return (ENOMEM);
  569 
  570                 /* Encrypt packet */
  571                 m1 = m;
  572                 while (m1) {
  573                         rc4_crypt(&d->rc4, mtod(m1, u_char *),
  574                             mtod(m1, u_char *), m1->m_len);
  575                         m1 = m1->m_next;
  576                 }
  577         }
  578 #endif
  579 
  580         /* Update coherency count for next time (12 bit arithmetic) */
  581         MPPC_CCOUNT_INC(d->cc);
  582 
  583         /* Install header */
  584         M_PREPEND(m, MPPC_HDRLEN, M_DONTWAIT);
  585         if (m != NULL)
  586                 *(mtod(m, uint16_t *)) = htons(header);
  587 
  588         *datap = m;
  589         return (*datap == NULL ? ENOBUFS : 0);
  590 }
  591 
  592 /*
  593  * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
  594  * The original mbuf is not free'd.
  595  */
  596 static int
  597 ng_mppc_decompress(node_p node, struct mbuf **datap)
  598 {
  599         const priv_p priv = NG_NODE_PRIVATE(node);
  600         struct ng_mppc_dir *const d = &priv->recv;
  601         u_int16_t header, cc;
  602         u_int numLost;
  603         struct mbuf *m = *datap;
  604 
  605         /* Pull off header */
  606         if (m->m_pkthdr.len < MPPC_HDRLEN) {
  607                 m_freem(m);
  608                 return (EINVAL);
  609         }
  610         m_copydata(m, 0, MPPC_HDRLEN, (caddr_t)&header);
  611         header = ntohs(header);
  612         cc = (header & MPPC_CCOUNT_MASK);
  613         m_adj(m, MPPC_HDRLEN);
  614 
  615         /* Check for an unexpected jump in the sequence number */
  616         numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK);
  617 
  618         /* If flushed bit set, we can always handle packet */
  619         if ((header & MPPC_FLAG_FLUSHED) != 0) {
  620 #ifdef NETGRAPH_MPPC_COMPRESSION
  621                 if (d->history != NULL)
  622                         MPPC_InitDecompressionHistory(d->history);
  623 #endif
  624 #ifdef NETGRAPH_MPPC_ENCRYPTION
  625                 if ((d->cfg.bits & MPPE_BITS) != 0) {
  626                         u_int rekey;
  627 
  628                         /* How many times are we going to have to re-key? */
  629                         rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ?
  630                             numLost : (numLost / (MPPE_UPDATE_MASK + 1));
  631                         if (rekey > MPPE_MAX_REKEY) {
  632                                 log(LOG_ERR, "%s: too many (%d) packets"
  633                                     " dropped, disabling node %p!",
  634                                     __func__, numLost, node);
  635                                 priv->recv.cfg.enable = 0;
  636                                 goto failed;
  637                         }
  638 
  639                         /* Re-key as necessary to catch up to peer */
  640                         while (d->cc != cc) {
  641                                 if ((d->cfg.bits & MPPE_STATELESS) != 0
  642                                     || (d->cc & MPPE_UPDATE_MASK)
  643                                       == MPPE_UPDATE_FLAG) {
  644                                         ng_mppc_updatekey(d->cfg.bits,
  645                                             d->cfg.startkey, d->key, &d->rc4);
  646                                 }
  647                                 MPPC_CCOUNT_INC(d->cc);
  648                         }
  649 
  650                         /* Reset key (except in stateless mode, see below) */
  651                         if ((d->cfg.bits & MPPE_STATELESS) == 0)
  652                                 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
  653                 }
  654 #endif
  655                 d->cc = cc;             /* skip over lost seq numbers */
  656                 numLost = 0;            /* act like no packets were lost */
  657         }
  658 
  659         /* Can't decode non-sequential packets without a flushed bit */
  660         if (numLost != 0)
  661                 goto failed;
  662 
  663         /* Decrypt packet */
  664         if ((header & MPPC_FLAG_ENCRYPTED) != 0) {
  665 #ifdef NETGRAPH_MPPC_ENCRYPTION
  666                 struct mbuf *m1;
  667 #endif
  668 
  669                 /* Are we not expecting encryption? */
  670                 if ((d->cfg.bits & MPPE_BITS) == 0) {
  671                         log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
  672                                 __func__, "encrypted");
  673                         goto failed;
  674                 }
  675 
  676 #ifdef NETGRAPH_MPPC_ENCRYPTION
  677                 /* Update key if it's time (always in stateless mode) */
  678                 if ((d->cfg.bits & MPPE_STATELESS) != 0
  679                     || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
  680                         ng_mppc_updatekey(d->cfg.bits,
  681                             d->cfg.startkey, d->key, &d->rc4);
  682                 }
  683 
  684                 /* We must own the mbuf chain exclusively to modify it. */
  685                 m = m_unshare(m, M_DONTWAIT);
  686                 if (m == NULL)
  687                         return (ENOMEM);
  688 
  689                 /* Decrypt packet */
  690                 m1 = m;
  691                 while (m1 != NULL) {
  692                         rc4_crypt(&d->rc4, mtod(m1, u_char *),
  693                             mtod(m1, u_char *), m1->m_len);
  694                         m1 = m1->m_next;
  695                 }
  696 #endif
  697         } else {
  698 
  699                 /* Are we expecting encryption? */
  700                 if ((d->cfg.bits & MPPE_BITS) != 0) {
  701                         log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
  702                                 __func__, "unencrypted");
  703                         goto failed;
  704                 }
  705         }
  706 
  707         /* Update coherency count for next time (12 bit arithmetic) */
  708         MPPC_CCOUNT_INC(d->cc);
  709 
  710         /* Check for unexpected compressed packet */
  711         if ((header & MPPC_FLAG_COMPRESSED) != 0
  712             && (d->cfg.bits & MPPC_BIT) == 0) {
  713                 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
  714                         __func__, "compressed");
  715 failed:
  716                 m_freem(m);
  717                 return (EINVAL);
  718         }
  719 
  720 #ifdef NETGRAPH_MPPC_COMPRESSION
  721         /* Decompress packet */
  722         if ((header & MPPC_FLAG_COMPRESSED) != 0) {
  723                 int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS;
  724                 u_char *decompbuf, *source, *dest;
  725                 u_long sourceCnt, destCnt;
  726                 int decomplen, rtn;
  727                 u_char *buf;
  728                 int len;
  729 
  730                 /* Copy payload into a contiguous region of memory. */
  731                 len = m->m_pkthdr.len;
  732                 buf = malloc(len, M_NETGRAPH_MPPC, M_NOWAIT);
  733                 if (buf == NULL) {
  734                         m_freem(m);
  735                         return (ENOMEM);
  736                 }
  737                 m_copydata(m, 0, len, (caddr_t)buf);
  738 
  739                 /* Allocate a buffer for decompressed data */
  740                 decompbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY,
  741                     M_NETGRAPH_MPPC, M_NOWAIT);
  742                 if (decompbuf == NULL) {
  743                         m_freem(m);
  744                         free(buf, M_NETGRAPH_MPPC);
  745                         return (ENOMEM);
  746                 }
  747                 decomplen = MPPC_DECOMP_BUFSIZE;
  748 
  749                 /* Prepare to decompress */
  750                 source = buf;
  751                 sourceCnt = len;
  752                 dest = decompbuf;
  753                 destCnt = decomplen;
  754                 if ((header & MPPC_FLAG_RESTART) != 0)
  755                         flags |= MPPC_RESTART_HISTORY;
  756 
  757                 /* Decompress */
  758                 rtn = MPPC_Decompress(&source, &dest,
  759                         &sourceCnt, &destCnt, d->history, flags);
  760 
  761                 /* Check return value */
  762                 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
  763                 if ((rtn & MPPC_DEST_EXHAUSTED) != 0
  764                     || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) {
  765                         log(LOG_ERR, "%s: decomp returned 0x%x",
  766                             __func__, rtn);
  767                         free(buf, M_NETGRAPH_MPPC);
  768                         free(decompbuf, M_NETGRAPH_MPPC);
  769                         goto failed;
  770                 }
  771 
  772                 /* Replace compressed data with decompressed data */
  773                 free(buf, M_NETGRAPH_MPPC);
  774                 len = decomplen - destCnt;
  775         
  776                 m_freem(m);
  777                 m = m_devget((caddr_t)decompbuf, len, 0, NULL, NULL);
  778                 free(decompbuf, M_NETGRAPH_MPPC);
  779         }
  780 #endif
  781 
  782         /* Return result in an mbuf */
  783         *datap = m;
  784         return (*datap == NULL ? ENOBUFS : 0);
  785 }
  786 
  787 /*
  788  * The peer has sent us a CCP ResetRequest, so reset our transmit state.
  789  */
  790 static void
  791 ng_mppc_reset_req(node_p node)
  792 {   
  793         const priv_p priv = NG_NODE_PRIVATE(node);
  794         struct ng_mppc_dir *const d = &priv->xmit;
  795 
  796 #ifdef NETGRAPH_MPPC_COMPRESSION
  797         if (d->history != NULL)
  798                 MPPC_InitCompressionHistory(d->history);
  799 #endif
  800 #ifdef NETGRAPH_MPPC_ENCRYPTION
  801         if ((d->cfg.bits & MPPE_STATELESS) == 0)
  802                 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
  803 #endif
  804         d->flushed = 1;
  805 }   
  806 
  807 #ifdef NETGRAPH_MPPC_ENCRYPTION
  808 /*
  809  * Generate a new encryption key
  810  */
  811 static void
  812 ng_mppc_getkey(const u_char *h, u_char *h2, int len)
  813 {
  814         static const u_char pad1[10] =
  815             { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
  816         static const u_char pad2[10] =
  817             { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, };
  818         u_char hash[20];
  819         SHA1_CTX c;
  820         int k;
  821 
  822         SHA1Init(&c);
  823         SHA1Update(&c, h, len);
  824         for (k = 0; k < 4; k++)
  825                 SHA1Update(&c, pad1, sizeof(pad1));
  826         SHA1Update(&c, h2, len);
  827         for (k = 0; k < 4; k++)
  828                 SHA1Update(&c, pad2, sizeof(pad2));
  829         SHA1Final(hash, &c);
  830         bcopy(hash, h2, len);
  831 }
  832 
  833 /*
  834  * Update the encryption key
  835  */
  836 static void
  837 ng_mppc_updatekey(u_int32_t bits,
  838         u_char *key0, u_char *key, struct rc4_state *rc4)
  839 { 
  840         const int keylen = KEYLEN(bits);
  841 
  842         ng_mppc_getkey(key0, key, keylen);
  843         rc4_init(rc4, key, keylen);
  844         rc4_crypt(rc4, key, key, keylen);
  845         if ((bits & MPPE_40) != 0)
  846                 bcopy(&ng_mppe_weakenkey, key, 3);
  847         else if ((bits & MPPE_56) != 0)
  848                 bcopy(&ng_mppe_weakenkey, key, 1);
  849         rc4_init(rc4, key, keylen);
  850 }
  851 #endif
  852 

Cache object: 42ab945c2011f3a9b3f9f23d59599853


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