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.3/sys/netgraph/ng_mppc.c 136588 2004-10-16 08:43:07Z cvs2svn $
   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 /*
   94  * When packets are lost with MPPE, we may have to re-key arbitrarily
   95  * many times to 'catch up' to the new jumped-ahead sequence number.
   96  * Since this can be expensive, we pose a limit on how many re-keyings
   97  * we will do at one time to avoid a possible D.O.S. vulnerability.
   98  * This should instead be a configurable parameter.
   99  */
  100 #define MPPE_MAX_REKEY          1000
  101 
  102 /* MPPC packet header bits */
  103 #define MPPC_FLAG_FLUSHED       0x8000          /* xmitter reset state */
  104 #define MPPC_FLAG_RESTART       0x4000          /* compress history restart */
  105 #define MPPC_FLAG_COMPRESSED    0x2000          /* packet is compresed */
  106 #define MPPC_FLAG_ENCRYPTED     0x1000          /* packet is encrypted */
  107 #define MPPC_CCOUNT_MASK        0x0fff          /* sequence number mask */
  108 
  109 #define MPPE_UPDATE_MASK        0xff            /* coherency count when we're */
  110 #define MPPE_UPDATE_FLAG        0xff            /*   supposed to update key */
  111 
  112 #define MPPC_COMP_OK            0x05
  113 #define MPPC_DECOMP_OK          0x05
  114 
  115 /* Per direction info */
  116 struct ng_mppc_dir {
  117         struct ng_mppc_config   cfg;            /* configuration */
  118         hook_p                  hook;           /* netgraph hook */
  119         u_int16_t               cc:12;          /* coherency count */
  120         u_char                  flushed;        /* clean history (xmit only) */
  121 #ifdef NETGRAPH_MPPC_COMPRESSION
  122         u_char                  *history;       /* compression history */
  123 #endif
  124 #ifdef NETGRAPH_MPPC_ENCRYPTION
  125         u_char                  key[MPPE_KEY_LEN];      /* session key */
  126         struct rc4_state        rc4;                    /* rc4 state */
  127 #endif
  128 };
  129 
  130 /* Node private data */
  131 struct ng_mppc_private {
  132         struct ng_mppc_dir      xmit;           /* compress/encrypt config */
  133         struct ng_mppc_dir      recv;           /* decompress/decrypt config */
  134         ng_ID_t                 ctrlnode;       /* path to controlling node */
  135 };
  136 typedef struct ng_mppc_private *priv_p;
  137 
  138 /* Netgraph node methods */
  139 static ng_constructor_t ng_mppc_constructor;
  140 static ng_rcvmsg_t      ng_mppc_rcvmsg;
  141 static ng_shutdown_t    ng_mppc_shutdown;
  142 static ng_newhook_t     ng_mppc_newhook;
  143 static ng_rcvdata_t     ng_mppc_rcvdata;
  144 static ng_disconnect_t  ng_mppc_disconnect;
  145 
  146 /* Helper functions */
  147 static int      ng_mppc_compress(node_p node,
  148                         struct mbuf *m, struct mbuf **resultp);
  149 static int      ng_mppc_decompress(node_p node,
  150                         struct mbuf *m, struct mbuf **resultp);
  151 static void     ng_mppc_getkey(const u_char *h, u_char *h2, int len);
  152 static void     ng_mppc_updatekey(u_int32_t bits,
  153                         u_char *key0, u_char *key, struct rc4_state *rc4);
  154 static void     ng_mppc_reset_req(node_p node);
  155 
  156 /* Node type descriptor */
  157 static struct ng_type ng_mppc_typestruct = {
  158         .version =      NG_ABI_VERSION,
  159         .name =         NG_MPPC_NODE_TYPE,
  160         .constructor =  ng_mppc_constructor,
  161         .rcvmsg =       ng_mppc_rcvmsg,
  162         .shutdown =     ng_mppc_shutdown,
  163         .newhook =      ng_mppc_newhook,
  164         .rcvdata =      ng_mppc_rcvdata,
  165         .disconnect =   ng_mppc_disconnect,
  166 };
  167 NETGRAPH_INIT(mppc, &ng_mppc_typestruct);
  168 
  169 #ifdef NETGRAPH_MPPC_ENCRYPTION
  170 /* Depend on separate rc4 module */
  171 MODULE_DEPEND(ng_mppc, rc4, 1, 1, 1);
  172 #endif
  173 
  174 /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */
  175 static const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e };
  176 
  177 #define ERROUT(x)       do { error = (x); goto done; } while (0)
  178 
  179 /************************************************************************
  180                         NETGRAPH NODE STUFF
  181  ************************************************************************/
  182 
  183 /*
  184  * Node type constructor
  185  */
  186 static int
  187 ng_mppc_constructor(node_p node)
  188 {
  189         priv_p priv;
  190 
  191         /* Allocate private structure */
  192         MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH_MPPC, M_NOWAIT | M_ZERO);
  193         if (priv == NULL)
  194                 return (ENOMEM);
  195 
  196         NG_NODE_SET_PRIVATE(node, priv);
  197 
  198         /* Done */
  199         return (0);
  200 }
  201 
  202 /*
  203  * Give our OK for a hook to be added
  204  */
  205 static int
  206 ng_mppc_newhook(node_p node, hook_p hook, const char *name)
  207 {
  208         const priv_p priv = NG_NODE_PRIVATE(node);
  209         hook_p *hookPtr;
  210 
  211         /* Check hook name */
  212         if (strcmp(name, NG_MPPC_HOOK_COMP) == 0)
  213                 hookPtr = &priv->xmit.hook;
  214         else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0)
  215                 hookPtr = &priv->recv.hook;
  216         else
  217                 return (EINVAL);
  218 
  219         /* See if already connected */
  220         if (*hookPtr != NULL)
  221                 return (EISCONN);
  222 
  223         /* OK */
  224         *hookPtr = hook;
  225         return (0);
  226 }
  227 
  228 /*
  229  * Receive a control message
  230  */
  231 static int
  232 ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook)
  233 {
  234         const priv_p priv = NG_NODE_PRIVATE(node);
  235         struct ng_mesg *resp = NULL;
  236         int error = 0;
  237         struct ng_mesg *msg;
  238 
  239         NGI_GET_MSG(item, msg);
  240         switch (msg->header.typecookie) {
  241         case NGM_MPPC_COOKIE:
  242                 switch (msg->header.cmd) {
  243                 case NGM_MPPC_CONFIG_COMP:
  244                 case NGM_MPPC_CONFIG_DECOMP:
  245                     {
  246                         struct ng_mppc_config *const cfg
  247                             = (struct ng_mppc_config *)msg->data;
  248                         const int isComp =
  249                             msg->header.cmd == NGM_MPPC_CONFIG_COMP;
  250                         struct ng_mppc_dir *const d = isComp ?
  251                             &priv->xmit : &priv->recv;
  252 
  253                         /* Check configuration */
  254                         if (msg->header.arglen != sizeof(*cfg))
  255                                 ERROUT(EINVAL);
  256                         if (cfg->enable) {
  257                                 if ((cfg->bits & ~MPPC_VALID_BITS) != 0)
  258                                         ERROUT(EINVAL);
  259 #ifndef NETGRAPH_MPPC_COMPRESSION
  260                                 if ((cfg->bits & MPPC_BIT) != 0)
  261                                         ERROUT(EPROTONOSUPPORT);
  262 #endif
  263 #ifndef NETGRAPH_MPPC_ENCRYPTION
  264                                 if ((cfg->bits & MPPE_BITS) != 0)
  265                                         ERROUT(EPROTONOSUPPORT);
  266 #endif
  267                         } else
  268                                 cfg->bits = 0;
  269 
  270                         /* Save return address so we can send reset-req's */
  271                         if (!isComp)
  272                                 priv->ctrlnode = NGI_RETADDR(item);
  273 
  274                         /* Configuration is OK, reset to it */
  275                         d->cfg = *cfg;
  276 
  277 #ifdef NETGRAPH_MPPC_COMPRESSION
  278                         /* Initialize state buffers for compression */
  279                         if (d->history != NULL) {
  280                                 FREE(d->history, M_NETGRAPH_MPPC);
  281                                 d->history = NULL;
  282                         }
  283                         if ((cfg->bits & MPPC_BIT) != 0) {
  284                                 MALLOC(d->history, u_char *,
  285                                     isComp ? MPPC_SizeOfCompressionHistory() :
  286                                     MPPC_SizeOfDecompressionHistory(),
  287                                     M_NETGRAPH_MPPC, M_NOWAIT);
  288                                 if (d->history == NULL)
  289                                         ERROUT(ENOMEM);
  290                                 if (isComp)
  291                                         MPPC_InitCompressionHistory(d->history);
  292                                 else {
  293                                         MPPC_InitDecompressionHistory(
  294                                             d->history);
  295                                 }
  296                         }
  297 #endif
  298 
  299 #ifdef NETGRAPH_MPPC_ENCRYPTION
  300                         /* Generate initial session keys for encryption */
  301                         if ((cfg->bits & MPPE_BITS) != 0) {
  302                                 const int keylen = KEYLEN(cfg->bits);
  303 
  304                                 bcopy(cfg->startkey, d->key, keylen);
  305                                 ng_mppc_getkey(cfg->startkey, d->key, keylen);
  306                                 if ((cfg->bits & MPPE_40) != 0)
  307                                         bcopy(&ng_mppe_weakenkey, d->key, 3);
  308                                 else if ((cfg->bits & MPPE_56) != 0)
  309                                         bcopy(&ng_mppe_weakenkey, d->key, 1);
  310                                 rc4_init(&d->rc4, d->key, keylen);
  311                         }
  312 #endif
  313 
  314                         /* Initialize other state */
  315                         d->cc = 0;
  316                         d->flushed = 0;
  317                         break;
  318                     }
  319 
  320                 case NGM_MPPC_RESETREQ:
  321                         ng_mppc_reset_req(node);
  322                         break;
  323 
  324                 default:
  325                         error = EINVAL;
  326                         break;
  327                 }
  328                 break;
  329         default:
  330                 error = EINVAL;
  331                 break;
  332         }
  333 done:
  334         NG_RESPOND_MSG(error, node, item, resp);
  335         NG_FREE_MSG(msg);
  336         return (error);
  337 }
  338 
  339 /*
  340  * Receive incoming data on our hook.
  341  */
  342 static int
  343 ng_mppc_rcvdata(hook_p hook, item_p item)
  344 {
  345         const node_p node = NG_HOOK_NODE(hook);
  346         const priv_p priv = NG_NODE_PRIVATE(node);
  347         struct mbuf *out;
  348         int error;
  349         struct mbuf *m;
  350 
  351         NGI_GET_M(item, m);
  352         /* Compress and/or encrypt */
  353         if (hook == priv->xmit.hook) {
  354                 if (!priv->xmit.cfg.enable) {
  355                         NG_FREE_M(m);
  356                         NG_FREE_ITEM(item);
  357                         return (ENXIO);
  358                 }
  359                 if ((error = ng_mppc_compress(node, m, &out)) != 0) {
  360                         NG_FREE_M(m);
  361                         NG_FREE_ITEM(item);
  362                         return(error);
  363                 }
  364                 NG_FREE_M(m);
  365                 NG_FWD_NEW_DATA(error, item, priv->xmit.hook, out);
  366                 return (error);
  367         }
  368 
  369         /* Decompress and/or decrypt */
  370         if (hook == priv->recv.hook) {
  371                 if (!priv->recv.cfg.enable) {
  372                         NG_FREE_M(m);
  373                         NG_FREE_ITEM(item);
  374                         return (ENXIO);
  375                 }
  376                 if ((error = ng_mppc_decompress(node, m, &out)) != 0) {
  377                         NG_FREE_M(m);
  378                         NG_FREE_ITEM(item);
  379                         if (error == EINVAL && priv->ctrlnode != 0) {
  380                                 struct ng_mesg *msg;
  381 
  382                                 /* Need to send a reset-request */
  383                                 NG_MKMESSAGE(msg, NGM_MPPC_COOKIE,
  384                                     NGM_MPPC_RESETREQ, 0, M_NOWAIT);
  385                                 if (msg == NULL)
  386                                         return (error);
  387                                 NG_SEND_MSG_ID(error, node, msg,
  388                                         priv->ctrlnode, 0); 
  389                         }
  390                         return (error);
  391                 }
  392                 NG_FREE_M(m);
  393                 NG_FWD_NEW_DATA(error, item, priv->recv.hook, out);
  394                 return (error);
  395         }
  396 
  397         /* Oops */
  398         panic("%s: unknown hook", __func__);
  399 #ifdef RESTARTABLE_PANICS
  400         return (EINVAL);
  401 #endif
  402 }
  403 
  404 /*
  405  * Destroy node
  406  */
  407 static int
  408 ng_mppc_shutdown(node_p node)
  409 {
  410         const priv_p priv = NG_NODE_PRIVATE(node);
  411 
  412         /* Take down netgraph node */
  413 #ifdef NETGRAPH_MPPC_COMPRESSION
  414         if (priv->xmit.history != NULL)
  415                 FREE(priv->xmit.history, M_NETGRAPH_MPPC);
  416         if (priv->recv.history != NULL)
  417                 FREE(priv->recv.history, M_NETGRAPH_MPPC);
  418 #endif
  419         bzero(priv, sizeof(*priv));
  420         FREE(priv, M_NETGRAPH_MPPC);
  421         NG_NODE_SET_PRIVATE(node, NULL);
  422         NG_NODE_UNREF(node);            /* let the node escape */
  423         return (0);
  424 }
  425 
  426 /*
  427  * Hook disconnection
  428  */
  429 static int
  430 ng_mppc_disconnect(hook_p hook)
  431 {
  432         const node_p node = NG_HOOK_NODE(hook);
  433         const priv_p priv = NG_NODE_PRIVATE(node);
  434 
  435         /* Zero out hook pointer */
  436         if (hook == priv->xmit.hook)
  437                 priv->xmit.hook = NULL;
  438         if (hook == priv->recv.hook)
  439                 priv->recv.hook = NULL;
  440 
  441         /* Go away if no longer connected */
  442         if ((NG_NODE_NUMHOOKS(node) == 0)
  443         && NG_NODE_IS_VALID(node))
  444                 ng_rmnode_self(node);
  445         return (0);
  446 }
  447 
  448 /************************************************************************
  449                         HELPER STUFF
  450  ************************************************************************/
  451 
  452 /*
  453  * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
  454  * The original mbuf is not free'd.
  455  */
  456 static int
  457 ng_mppc_compress(node_p node, struct mbuf *m, struct mbuf **resultp)
  458 {
  459         const priv_p priv = NG_NODE_PRIVATE(node);
  460         struct ng_mppc_dir *const d = &priv->xmit;
  461         u_char *inbuf, *outbuf;
  462         int outlen, inlen;
  463         u_int16_t header;
  464 
  465         /* Initialize */
  466         *resultp = NULL;
  467         header = d->cc;
  468         if (d->flushed) {
  469                 header |= MPPC_FLAG_FLUSHED;
  470                 d->flushed = 0;
  471         }
  472 
  473         /* Work with contiguous regions of memory */
  474         inlen = m->m_pkthdr.len;
  475         MALLOC(inbuf, u_char *, inlen, M_NETGRAPH_MPPC, M_NOWAIT);
  476         if (inbuf == NULL)
  477                 return (ENOMEM);
  478         m_copydata(m, 0, inlen, (caddr_t)inbuf);
  479         if ((d->cfg.bits & MPPC_BIT) != 0)
  480                 outlen = MPPC_MAX_BLOWUP(inlen);
  481         else
  482                 outlen = MPPC_HDRLEN + inlen;
  483         MALLOC(outbuf, u_char *, outlen, M_NETGRAPH_MPPC, M_NOWAIT);
  484         if (outbuf == NULL) {
  485                 FREE(inbuf, M_NETGRAPH_MPPC);
  486                 return (ENOMEM);
  487         }
  488 
  489         /* Compress "inbuf" into "outbuf" (if compression enabled) */
  490 #ifdef NETGRAPH_MPPC_COMPRESSION
  491         if ((d->cfg.bits & MPPC_BIT) != 0) {
  492                 u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS;
  493                 u_char *source, *dest;
  494                 u_long sourceCnt, destCnt;
  495                 int rtn;
  496 
  497                 /* Prepare to compress */
  498                 source = inbuf;
  499                 sourceCnt = inlen;
  500                 dest = outbuf + MPPC_HDRLEN;
  501                 destCnt = outlen - MPPC_HDRLEN;
  502                 if ((d->cfg.bits & MPPE_STATELESS) == 0)
  503                         flags |= MPPC_SAVE_HISTORY;
  504 
  505                 /* Compress */
  506                 rtn = MPPC_Compress(&source, &dest, &sourceCnt,
  507                         &destCnt, d->history, flags, 0);
  508 
  509                 /* Check return value */
  510                 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
  511                 if ((rtn & MPPC_EXPANDED) == 0
  512                     && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) {
  513                         outlen -= destCnt;     
  514                         header |= MPPC_FLAG_COMPRESSED;
  515                         if ((rtn & MPPC_RESTART_HISTORY) != 0)
  516                                 header |= MPPC_FLAG_RESTART;  
  517                 }
  518                 d->flushed = (rtn & MPPC_EXPANDED) != 0
  519                     || (flags & MPPC_SAVE_HISTORY) == 0;
  520         }
  521 #endif
  522 
  523         /* If we did not compress this packet, copy it to output buffer */
  524         if ((header & MPPC_FLAG_COMPRESSED) == 0) {
  525                 bcopy(inbuf, outbuf + MPPC_HDRLEN, inlen);
  526                 outlen = MPPC_HDRLEN + inlen;
  527         }
  528         FREE(inbuf, M_NETGRAPH_MPPC);
  529 
  530         /* Always set the flushed bit in stateless mode */
  531         if ((d->cfg.bits & MPPE_STATELESS) != 0)
  532                 header |= MPPC_FLAG_FLUSHED;
  533 
  534         /* Now encrypt packet (if encryption enabled) */
  535 #ifdef NETGRAPH_MPPC_ENCRYPTION
  536         if ((d->cfg.bits & MPPE_BITS) != 0) {
  537 
  538                 /* Set header bits; need to reset key if we say we did */
  539                 header |= MPPC_FLAG_ENCRYPTED;
  540                 if ((header & MPPC_FLAG_FLUSHED) != 0)
  541                         rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
  542 
  543                 /* Update key if it's time */
  544                 if ((d->cfg.bits & MPPE_STATELESS) != 0
  545                     || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
  546                           ng_mppc_updatekey(d->cfg.bits,
  547                               d->cfg.startkey, d->key, &d->rc4);
  548                 }
  549 
  550                 /* Encrypt packet */
  551                 rc4_crypt(&d->rc4, outbuf + MPPC_HDRLEN,
  552                         outbuf + MPPC_HDRLEN, outlen - MPPC_HDRLEN);
  553         }
  554 #endif
  555 
  556         /* Update sequence number */
  557         d->cc++;
  558 
  559         /* Install header */
  560         *((u_int16_t *)outbuf) = htons(header);
  561 
  562         /* Return packet in an mbuf */
  563         *resultp = m_devget((caddr_t)outbuf, outlen, 0, NULL, NULL);
  564         FREE(outbuf, M_NETGRAPH_MPPC);
  565         return (*resultp == NULL ? ENOBUFS : 0);
  566 }
  567 
  568 /*
  569  * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
  570  * The original mbuf is not free'd.
  571  */
  572 static int
  573 ng_mppc_decompress(node_p node, struct mbuf *m, struct mbuf **resultp)
  574 {
  575         const priv_p priv = NG_NODE_PRIVATE(node);
  576         struct ng_mppc_dir *const d = &priv->recv;
  577         u_int16_t header, cc;
  578         u_int numLost;
  579         u_char *buf;
  580         int len;
  581 
  582         /* Pull off header */
  583         if (m->m_pkthdr.len < MPPC_HDRLEN)
  584                 return (EINVAL);
  585         m_copydata(m, 0, MPPC_HDRLEN, (caddr_t)&header);
  586         header = ntohs(header);
  587         cc = (header & MPPC_CCOUNT_MASK);
  588 
  589         /* Copy payload into a contiguous region of memory */
  590         len = m->m_pkthdr.len - MPPC_HDRLEN;
  591         MALLOC(buf, u_char *, len, M_NETGRAPH_MPPC, M_NOWAIT);
  592         if (buf == NULL)
  593                 return (ENOMEM);
  594         m_copydata(m, MPPC_HDRLEN, len, (caddr_t)buf);
  595 
  596         /* Check for an unexpected jump in the sequence number */
  597         numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK);
  598 
  599         /* If flushed bit set, we can always handle packet */
  600         if ((header & MPPC_FLAG_FLUSHED) != 0) {
  601 #ifdef NETGRAPH_MPPC_COMPRESSION
  602                 if (d->history != NULL)
  603                         MPPC_InitDecompressionHistory(d->history);
  604 #endif
  605 #ifdef NETGRAPH_MPPC_ENCRYPTION
  606                 if ((d->cfg.bits & MPPE_BITS) != 0) {
  607                         u_int rekey;
  608 
  609                         /* How many times are we going to have to re-key? */
  610                         rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ?
  611                             numLost : (numLost / (MPPE_UPDATE_MASK + 1));
  612                         if (rekey > MPPE_MAX_REKEY) {
  613                                 log(LOG_ERR, "%s: too many (%d) packets"
  614                                     " dropped, disabling node %p!",
  615                                     __func__, numLost, node);
  616                                 priv->recv.cfg.enable = 0;
  617                                 goto failed;
  618                         }
  619 
  620                         /* Re-key as necessary to catch up to peer */
  621                         while (d->cc != cc) {
  622                                 if ((d->cfg.bits & MPPE_STATELESS) != 0
  623                                     || (d->cc & MPPE_UPDATE_MASK)
  624                                       == MPPE_UPDATE_FLAG) {
  625                                         ng_mppc_updatekey(d->cfg.bits,
  626                                             d->cfg.startkey, d->key, &d->rc4);
  627                                 }
  628                                 d->cc++;
  629                         }
  630 
  631                         /* Reset key (except in stateless mode, see below) */
  632                         if ((d->cfg.bits & MPPE_STATELESS) == 0)
  633                                 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
  634                 }
  635 #endif
  636                 d->cc = cc;             /* skip over lost seq numbers */
  637                 numLost = 0;            /* act like no packets were lost */
  638         }
  639 
  640         /* Can't decode non-sequential packets without a flushed bit */
  641         if (numLost != 0)
  642                 goto failed;
  643 
  644         /* Decrypt packet */
  645         if ((header & MPPC_FLAG_ENCRYPTED) != 0) {
  646 
  647                 /* Are we not expecting encryption? */
  648                 if ((d->cfg.bits & MPPE_BITS) == 0) {
  649                         log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
  650                                 __func__, "encrypted");
  651                         goto failed;
  652                 }
  653 
  654 #ifdef NETGRAPH_MPPC_ENCRYPTION
  655                 /* Update key if it's time (always in stateless mode) */
  656                 if ((d->cfg.bits & MPPE_STATELESS) != 0
  657                     || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
  658                         ng_mppc_updatekey(d->cfg.bits,
  659                             d->cfg.startkey, d->key, &d->rc4);
  660                 }
  661 
  662                 /* Decrypt packet */
  663                 rc4_crypt(&d->rc4, buf, buf, len);
  664 #endif
  665         } else {
  666 
  667                 /* Are we expecting encryption? */
  668                 if ((d->cfg.bits & MPPE_BITS) != 0) {
  669                         log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
  670                                 __func__, "unencrypted");
  671                         goto failed;
  672                 }
  673         }
  674 
  675         /* Update coherency count for next time (12 bit arithmetic) */
  676         d->cc++;
  677 
  678         /* Check for unexpected compressed packet */
  679         if ((header & MPPC_FLAG_COMPRESSED) != 0
  680             && (d->cfg.bits & MPPC_BIT) == 0) {
  681                 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
  682                         __func__, "compressed");
  683 failed:
  684                 FREE(buf, M_NETGRAPH_MPPC);
  685                 return (EINVAL);
  686         }
  687 
  688 #ifdef NETGRAPH_MPPC_COMPRESSION
  689         /* Decompress packet */
  690         if ((header & MPPC_FLAG_COMPRESSED) != 0) {
  691                 int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS;
  692                 u_char *decompbuf, *source, *dest;
  693                 u_long sourceCnt, destCnt;
  694                 int decomplen, rtn;
  695 
  696                 /* Allocate a buffer for decompressed data */
  697                 MALLOC(decompbuf, u_char *, MPPC_DECOMP_BUFSIZE
  698                     + MPPC_DECOMP_SAFETY, M_NETGRAPH_MPPC, M_NOWAIT);
  699                 if (decompbuf == NULL) {
  700                         FREE(buf, M_NETGRAPH_MPPC);
  701                         return (ENOMEM);
  702                 }
  703                 decomplen = MPPC_DECOMP_BUFSIZE;
  704 
  705                 /* Prepare to decompress */
  706                 source = buf;
  707                 sourceCnt = len;
  708                 dest = decompbuf;
  709                 destCnt = decomplen;
  710                 if ((header & MPPC_FLAG_RESTART) != 0)
  711                         flags |= MPPC_RESTART_HISTORY;
  712 
  713                 /* Decompress */
  714                 rtn = MPPC_Decompress(&source, &dest,
  715                         &sourceCnt, &destCnt, d->history, flags);
  716 
  717                 /* Check return value */
  718                 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
  719                 if ((rtn & MPPC_DEST_EXHAUSTED) != 0
  720                     || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) {
  721                         log(LOG_ERR, "%s: decomp returned 0x%x",
  722                             __func__, rtn);
  723                         FREE(decompbuf, M_NETGRAPH_MPPC);
  724                         goto failed;
  725                 }
  726 
  727                 /* Replace compressed data with decompressed data */
  728                 FREE(buf, M_NETGRAPH_MPPC);
  729                 buf = decompbuf;
  730                 len = decomplen - destCnt;
  731         }
  732 #endif
  733 
  734         /* Return result in an mbuf */
  735         *resultp = m_devget((caddr_t)buf, len, 0, NULL, NULL);
  736         FREE(buf, M_NETGRAPH_MPPC);
  737         return (*resultp == NULL ? ENOBUFS : 0);
  738 }
  739 
  740 /*
  741  * The peer has sent us a CCP ResetRequest, so reset our transmit state.
  742  */
  743 static void
  744 ng_mppc_reset_req(node_p node)
  745 {   
  746         const priv_p priv = NG_NODE_PRIVATE(node);
  747         struct ng_mppc_dir *const d = &priv->xmit;
  748 
  749 #ifdef NETGRAPH_MPPC_COMPRESSION
  750         if (d->history != NULL)
  751                 MPPC_InitCompressionHistory(d->history);
  752 #endif
  753 #ifdef NETGRAPH_MPPC_ENCRYPTION
  754         if ((d->cfg.bits & MPPE_STATELESS) == 0)
  755                 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
  756 #endif
  757         d->flushed = 1;
  758 }   
  759 
  760 /*
  761  * Generate a new encryption key
  762  */
  763 static void
  764 ng_mppc_getkey(const u_char *h, u_char *h2, int len)
  765 {
  766         static const u_char pad1[10] =
  767             { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
  768         static const u_char pad2[10] =
  769             { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, };
  770         u_char hash[20];
  771         SHA1_CTX c;
  772         int k;
  773 
  774         bzero(&hash, sizeof(hash));
  775         SHA1Init(&c);
  776         SHA1Update(&c, h, len);
  777         for (k = 0; k < 4; k++)
  778                 SHA1Update(&c, pad1, sizeof(pad2));
  779         SHA1Update(&c, h2, len);
  780         for (k = 0; k < 4; k++)
  781                 SHA1Update(&c, pad2, sizeof(pad2));
  782         SHA1Final(hash, &c);
  783         bcopy(hash, h2, len);
  784 }
  785 
  786 /*
  787  * Update the encryption key
  788  */
  789 static void
  790 ng_mppc_updatekey(u_int32_t bits,
  791         u_char *key0, u_char *key, struct rc4_state *rc4)
  792 { 
  793         const int keylen = KEYLEN(bits);
  794 
  795         ng_mppc_getkey(key0, key, keylen);
  796         rc4_init(rc4, key, keylen);
  797         rc4_crypt(rc4, key, key, keylen);
  798         if ((bits & MPPE_40) != 0)
  799                 bcopy(&ng_mppe_weakenkey, key, 3);
  800         else if ((bits & MPPE_56) != 0)
  801                 bcopy(&ng_mppe_weakenkey, key, 1);
  802         rc4_init(rc4, key, keylen);
  803 }
  804 

Cache object: 6fa46bfb9fe8c2fc94890f5a49eef27b


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