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

Cache object: 339bc0289039d0ecefd09d3e63f4f462


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