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

Cache object: abe1381e34ac4edb20941b5d494ab723


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