1af7ab184SArchie Cobbs /* 2af7ab184SArchie Cobbs * ng_mppc.c 3c398230bSWarner Losh */ 4c398230bSWarner Losh 5c398230bSWarner Losh /*- 6af7ab184SArchie Cobbs * Copyright (c) 1996-2000 Whistle Communications, Inc. 7af7ab184SArchie Cobbs * All rights reserved. 8af7ab184SArchie Cobbs * 9af7ab184SArchie Cobbs * Subject to the following obligations and disclaimer of warranty, use and 10af7ab184SArchie Cobbs * redistribution of this software, in source or object code forms, with or 11af7ab184SArchie Cobbs * without modifications are expressly permitted by Whistle Communications; 12af7ab184SArchie Cobbs * provided, however, that: 13af7ab184SArchie Cobbs * 1. Any and all reproductions of the source or object code must include the 14af7ab184SArchie Cobbs * copyright notice above and the following disclaimer of warranties; and 15af7ab184SArchie Cobbs * 2. No rights are granted, in any manner or form, to use Whistle 16af7ab184SArchie Cobbs * Communications, Inc. trademarks, including the mark "WHISTLE 17af7ab184SArchie Cobbs * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 18af7ab184SArchie Cobbs * such appears in the above copyright notice or in the software. 19af7ab184SArchie Cobbs * 20af7ab184SArchie Cobbs * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 21af7ab184SArchie Cobbs * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 22af7ab184SArchie Cobbs * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 23af7ab184SArchie Cobbs * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 24af7ab184SArchie Cobbs * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 25af7ab184SArchie Cobbs * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 26af7ab184SArchie Cobbs * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 27af7ab184SArchie Cobbs * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 28af7ab184SArchie Cobbs * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 29af7ab184SArchie Cobbs * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 30af7ab184SArchie Cobbs * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 31af7ab184SArchie Cobbs * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 32af7ab184SArchie Cobbs * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 33af7ab184SArchie Cobbs * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34af7ab184SArchie Cobbs * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35af7ab184SArchie Cobbs * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 36af7ab184SArchie Cobbs * OF SUCH DAMAGE. 37af7ab184SArchie Cobbs * 38cc3bbd68SJulian Elischer * Author: Archie Cobbs <archie@freebsd.org> 39af7ab184SArchie Cobbs * 40af7ab184SArchie Cobbs * $Whistle: ng_mppc.c,v 1.4 1999/11/25 00:10:12 archie Exp $ 41af7ab184SArchie Cobbs * $FreeBSD$ 42af7ab184SArchie Cobbs */ 43af7ab184SArchie Cobbs 44af7ab184SArchie Cobbs /* 45af7ab184SArchie Cobbs * Microsoft PPP compression (MPPC) and encryption (MPPE) netgraph node type. 46af7ab184SArchie Cobbs * 47af7ab184SArchie Cobbs * You must define one or both of the NETGRAPH_MPPC_COMPRESSION and/or 48af7ab184SArchie Cobbs * NETGRAPH_MPPC_ENCRYPTION options for this node type to be useful. 49af7ab184SArchie Cobbs */ 50af7ab184SArchie Cobbs 51af7ab184SArchie Cobbs #include <sys/param.h> 52af7ab184SArchie Cobbs #include <sys/systm.h> 53af7ab184SArchie Cobbs #include <sys/kernel.h> 54af7ab184SArchie Cobbs #include <sys/mbuf.h> 55af7ab184SArchie Cobbs #include <sys/malloc.h> 5639228864SAlexander Motin #include <sys/endian.h> 57af7ab184SArchie Cobbs #include <sys/errno.h> 58af7ab184SArchie Cobbs #include <sys/syslog.h> 59af7ab184SArchie Cobbs 60af7ab184SArchie Cobbs #include <netgraph/ng_message.h> 61af7ab184SArchie Cobbs #include <netgraph/netgraph.h> 62af7ab184SArchie Cobbs #include <netgraph/ng_mppc.h> 63af7ab184SArchie Cobbs 64af7ab184SArchie Cobbs #include "opt_netgraph.h" 65af7ab184SArchie Cobbs 66af7ab184SArchie Cobbs #if !defined(NETGRAPH_MPPC_COMPRESSION) && !defined(NETGRAPH_MPPC_ENCRYPTION) 6710d645b7SYaroslav Tykhiy #ifdef KLD_MODULE 6810d645b7SYaroslav Tykhiy /* XXX NETGRAPH_MPPC_COMPRESSION isn't functional yet */ 6910d645b7SYaroslav Tykhiy #define NETGRAPH_MPPC_ENCRYPTION 7010d645b7SYaroslav Tykhiy #else 7110d645b7SYaroslav Tykhiy /* This case is indicative of an error in sys/conf files */ 72af7ab184SArchie Cobbs #error Need either NETGRAPH_MPPC_COMPRESSION or NETGRAPH_MPPC_ENCRYPTION 73af7ab184SArchie Cobbs #endif 7410d645b7SYaroslav Tykhiy #endif 75af7ab184SArchie Cobbs 769c8c302fSJulian Elischer #ifdef NG_SEPARATE_MALLOC 779c8c302fSJulian Elischer MALLOC_DEFINE(M_NETGRAPH_MPPC, "netgraph_mppc", "netgraph mppc node "); 789c8c302fSJulian Elischer #else 799c8c302fSJulian Elischer #define M_NETGRAPH_MPPC M_NETGRAPH 809c8c302fSJulian Elischer #endif 819c8c302fSJulian Elischer 82af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION 83af7ab184SArchie Cobbs /* XXX this file doesn't exist yet, but hopefully someday it will... */ 84af7ab184SArchie Cobbs #include <net/mppc.h> 85af7ab184SArchie Cobbs #endif 86af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION 87af7ab184SArchie Cobbs #include <crypto/rc4/rc4.h> 88af7ab184SArchie Cobbs #endif 89af7ab184SArchie Cobbs #include <crypto/sha1.h> 90af7ab184SArchie Cobbs 91af7ab184SArchie Cobbs /* Decompression blowup */ 92af7ab184SArchie Cobbs #define MPPC_DECOMP_BUFSIZE 8092 /* allocate buffer this big */ 93af7ab184SArchie Cobbs #define MPPC_DECOMP_SAFETY 100 /* plus this much margin */ 94af7ab184SArchie Cobbs 95af7ab184SArchie Cobbs /* MPPC/MPPE header length */ 96af7ab184SArchie Cobbs #define MPPC_HDRLEN 2 97af7ab184SArchie Cobbs 98af7ab184SArchie Cobbs /* Key length */ 99af7ab184SArchie Cobbs #define KEYLEN(b) (((b) & MPPE_128) ? 16 : 8) 100af7ab184SArchie Cobbs 101f3059f39SArchie Cobbs /* 102f3059f39SArchie Cobbs * When packets are lost with MPPE, we may have to re-key arbitrarily 103f3059f39SArchie Cobbs * many times to 'catch up' to the new jumped-ahead sequence number. 104f3059f39SArchie Cobbs * Since this can be expensive, we pose a limit on how many re-keyings 105f3059f39SArchie Cobbs * we will do at one time to avoid a possible D.O.S. vulnerability. 106f3059f39SArchie Cobbs * This should instead be a configurable parameter. 107f3059f39SArchie Cobbs */ 108f3059f39SArchie Cobbs #define MPPE_MAX_REKEY 1000 109af7ab184SArchie Cobbs 110af7ab184SArchie Cobbs /* MPPC packet header bits */ 111af7ab184SArchie Cobbs #define MPPC_FLAG_FLUSHED 0x8000 /* xmitter reset state */ 112af7ab184SArchie Cobbs #define MPPC_FLAG_RESTART 0x4000 /* compress history restart */ 113af7ab184SArchie Cobbs #define MPPC_FLAG_COMPRESSED 0x2000 /* packet is compresed */ 114af7ab184SArchie Cobbs #define MPPC_FLAG_ENCRYPTED 0x1000 /* packet is encrypted */ 115af7ab184SArchie Cobbs #define MPPC_CCOUNT_MASK 0x0fff /* sequence number mask */ 116af7ab184SArchie Cobbs 117755bc287SAlexander Motin #define MPPC_CCOUNT_INC(d) ((d) = (((d) + 1) & MPPC_CCOUNT_MASK)) 118755bc287SAlexander Motin 119af7ab184SArchie Cobbs #define MPPE_UPDATE_MASK 0xff /* coherency count when we're */ 120af7ab184SArchie Cobbs #define MPPE_UPDATE_FLAG 0xff /* supposed to update key */ 121af7ab184SArchie Cobbs 122af7ab184SArchie Cobbs #define MPPC_COMP_OK 0x05 123af7ab184SArchie Cobbs #define MPPC_DECOMP_OK 0x05 124af7ab184SArchie Cobbs 125af7ab184SArchie Cobbs /* Per direction info */ 126af7ab184SArchie Cobbs struct ng_mppc_dir { 127af7ab184SArchie Cobbs struct ng_mppc_config cfg; /* configuration */ 128af7ab184SArchie Cobbs hook_p hook; /* netgraph hook */ 129af7ab184SArchie Cobbs u_int16_t cc:12; /* coherency count */ 130af7ab184SArchie Cobbs u_char flushed; /* clean history (xmit only) */ 131af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION 132af7ab184SArchie Cobbs u_char *history; /* compression history */ 133af7ab184SArchie Cobbs #endif 134af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION 135af7ab184SArchie Cobbs u_char key[MPPE_KEY_LEN]; /* session key */ 136af7ab184SArchie Cobbs struct rc4_state rc4; /* rc4 state */ 137af7ab184SArchie Cobbs #endif 138af7ab184SArchie Cobbs }; 139af7ab184SArchie Cobbs 140af7ab184SArchie Cobbs /* Node private data */ 141af7ab184SArchie Cobbs struct ng_mppc_private { 142af7ab184SArchie Cobbs struct ng_mppc_dir xmit; /* compress/encrypt config */ 143af7ab184SArchie Cobbs struct ng_mppc_dir recv; /* decompress/decrypt config */ 144069154d5SJulian Elischer ng_ID_t ctrlnode; /* path to controlling node */ 145af7ab184SArchie Cobbs }; 146af7ab184SArchie Cobbs typedef struct ng_mppc_private *priv_p; 147af7ab184SArchie Cobbs 148af7ab184SArchie Cobbs /* Netgraph node methods */ 149af7ab184SArchie Cobbs static ng_constructor_t ng_mppc_constructor; 150af7ab184SArchie Cobbs static ng_rcvmsg_t ng_mppc_rcvmsg; 151069154d5SJulian Elischer static ng_shutdown_t ng_mppc_shutdown; 152af7ab184SArchie Cobbs static ng_newhook_t ng_mppc_newhook; 153af7ab184SArchie Cobbs static ng_rcvdata_t ng_mppc_rcvdata; 154af7ab184SArchie Cobbs static ng_disconnect_t ng_mppc_disconnect; 155af7ab184SArchie Cobbs 156af7ab184SArchie Cobbs /* Helper functions */ 157af7ab184SArchie Cobbs static int ng_mppc_compress(node_p node, 158ce52e8f4SAlexander Motin struct mbuf **datap); 159af7ab184SArchie Cobbs static int ng_mppc_decompress(node_p node, 160ce52e8f4SAlexander Motin struct mbuf **datap); 16106c51e6eSAlexander Motin #ifdef NETGRAPH_MPPC_ENCRYPTION 162af7ab184SArchie Cobbs static void ng_mppc_getkey(const u_char *h, u_char *h2, int len); 163af7ab184SArchie Cobbs static void ng_mppc_updatekey(u_int32_t bits, 164af7ab184SArchie Cobbs u_char *key0, u_char *key, struct rc4_state *rc4); 16506c51e6eSAlexander Motin #endif 166af7ab184SArchie Cobbs static void ng_mppc_reset_req(node_p node); 167af7ab184SArchie Cobbs 168af7ab184SArchie Cobbs /* Node type descriptor */ 169af7ab184SArchie Cobbs static struct ng_type ng_mppc_typestruct = { 170f8aae777SJulian Elischer .version = NG_ABI_VERSION, 171f8aae777SJulian Elischer .name = NG_MPPC_NODE_TYPE, 172f8aae777SJulian Elischer .constructor = ng_mppc_constructor, 173f8aae777SJulian Elischer .rcvmsg = ng_mppc_rcvmsg, 174f8aae777SJulian Elischer .shutdown = ng_mppc_shutdown, 175f8aae777SJulian Elischer .newhook = ng_mppc_newhook, 176f8aae777SJulian Elischer .rcvdata = ng_mppc_rcvdata, 177f8aae777SJulian Elischer .disconnect = ng_mppc_disconnect, 178af7ab184SArchie Cobbs }; 179af7ab184SArchie Cobbs NETGRAPH_INIT(mppc, &ng_mppc_typestruct); 180af7ab184SArchie Cobbs 181233896e9SDoug Ambrisko #ifdef NETGRAPH_MPPC_ENCRYPTION 182233896e9SDoug Ambrisko /* Depend on separate rc4 module */ 183233896e9SDoug Ambrisko MODULE_DEPEND(ng_mppc, rc4, 1, 1, 1); 184233896e9SDoug Ambrisko #endif 185233896e9SDoug Ambrisko 18634fd2381SArchie Cobbs /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */ 187af7ab184SArchie Cobbs static const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e }; 188af7ab184SArchie Cobbs 189af7ab184SArchie Cobbs #define ERROUT(x) do { error = (x); goto done; } while (0) 190af7ab184SArchie Cobbs 191af7ab184SArchie Cobbs /************************************************************************ 192af7ab184SArchie Cobbs NETGRAPH NODE STUFF 193af7ab184SArchie Cobbs ************************************************************************/ 194af7ab184SArchie Cobbs 195af7ab184SArchie Cobbs /* 196af7ab184SArchie Cobbs * Node type constructor 197af7ab184SArchie Cobbs */ 198af7ab184SArchie Cobbs static int 199069154d5SJulian Elischer ng_mppc_constructor(node_p node) 200af7ab184SArchie Cobbs { 201af7ab184SArchie Cobbs priv_p priv; 202af7ab184SArchie Cobbs 203af7ab184SArchie Cobbs /* Allocate private structure */ 204*674d86bfSGleb Smirnoff priv = malloc(sizeof(*priv), M_NETGRAPH_MPPC, M_WAITOK | M_ZERO); 205af7ab184SArchie Cobbs 20630400f03SJulian Elischer NG_NODE_SET_PRIVATE(node, priv); 207af7ab184SArchie Cobbs 2082f07580bSGleb Smirnoff /* This node is not thread safe. */ 2092f07580bSGleb Smirnoff NG_NODE_FORCE_WRITER(node); 2102f07580bSGleb Smirnoff 211af7ab184SArchie Cobbs /* Done */ 212af7ab184SArchie Cobbs return (0); 213af7ab184SArchie Cobbs } 214af7ab184SArchie Cobbs 215af7ab184SArchie Cobbs /* 216af7ab184SArchie Cobbs * Give our OK for a hook to be added 217af7ab184SArchie Cobbs */ 218af7ab184SArchie Cobbs static int 219af7ab184SArchie Cobbs ng_mppc_newhook(node_p node, hook_p hook, const char *name) 220af7ab184SArchie Cobbs { 22130400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 222af7ab184SArchie Cobbs hook_p *hookPtr; 223af7ab184SArchie Cobbs 224af7ab184SArchie Cobbs /* Check hook name */ 225af7ab184SArchie Cobbs if (strcmp(name, NG_MPPC_HOOK_COMP) == 0) 226af7ab184SArchie Cobbs hookPtr = &priv->xmit.hook; 227af7ab184SArchie Cobbs else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0) 228af7ab184SArchie Cobbs hookPtr = &priv->recv.hook; 229af7ab184SArchie Cobbs else 230af7ab184SArchie Cobbs return (EINVAL); 231af7ab184SArchie Cobbs 232af7ab184SArchie Cobbs /* See if already connected */ 233af7ab184SArchie Cobbs if (*hookPtr != NULL) 234af7ab184SArchie Cobbs return (EISCONN); 235af7ab184SArchie Cobbs 236af7ab184SArchie Cobbs /* OK */ 237af7ab184SArchie Cobbs *hookPtr = hook; 238af7ab184SArchie Cobbs return (0); 239af7ab184SArchie Cobbs } 240af7ab184SArchie Cobbs 241af7ab184SArchie Cobbs /* 242af7ab184SArchie Cobbs * Receive a control message 243af7ab184SArchie Cobbs */ 244af7ab184SArchie Cobbs static int 245069154d5SJulian Elischer ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook) 246af7ab184SArchie Cobbs { 24730400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 248af7ab184SArchie Cobbs struct ng_mesg *resp = NULL; 249af7ab184SArchie Cobbs int error = 0; 250069154d5SJulian Elischer struct ng_mesg *msg; 251af7ab184SArchie Cobbs 252069154d5SJulian Elischer NGI_GET_MSG(item, msg); 253af7ab184SArchie Cobbs switch (msg->header.typecookie) { 254af7ab184SArchie Cobbs case NGM_MPPC_COOKIE: 255af7ab184SArchie Cobbs switch (msg->header.cmd) { 256af7ab184SArchie Cobbs case NGM_MPPC_CONFIG_COMP: 257af7ab184SArchie Cobbs case NGM_MPPC_CONFIG_DECOMP: 258af7ab184SArchie Cobbs { 259af7ab184SArchie Cobbs struct ng_mppc_config *const cfg 260af7ab184SArchie Cobbs = (struct ng_mppc_config *)msg->data; 261af7ab184SArchie Cobbs const int isComp = 262af7ab184SArchie Cobbs msg->header.cmd == NGM_MPPC_CONFIG_COMP; 263af7ab184SArchie Cobbs struct ng_mppc_dir *const d = isComp ? 264af7ab184SArchie Cobbs &priv->xmit : &priv->recv; 265af7ab184SArchie Cobbs 266af7ab184SArchie Cobbs /* Check configuration */ 267af7ab184SArchie Cobbs if (msg->header.arglen != sizeof(*cfg)) 268af7ab184SArchie Cobbs ERROUT(EINVAL); 269af7ab184SArchie Cobbs if (cfg->enable) { 270af7ab184SArchie Cobbs if ((cfg->bits & ~MPPC_VALID_BITS) != 0) 271af7ab184SArchie Cobbs ERROUT(EINVAL); 272af7ab184SArchie Cobbs #ifndef NETGRAPH_MPPC_COMPRESSION 273af7ab184SArchie Cobbs if ((cfg->bits & MPPC_BIT) != 0) 274af7ab184SArchie Cobbs ERROUT(EPROTONOSUPPORT); 275af7ab184SArchie Cobbs #endif 276af7ab184SArchie Cobbs #ifndef NETGRAPH_MPPC_ENCRYPTION 277af7ab184SArchie Cobbs if ((cfg->bits & MPPE_BITS) != 0) 278af7ab184SArchie Cobbs ERROUT(EPROTONOSUPPORT); 279af7ab184SArchie Cobbs #endif 280af7ab184SArchie Cobbs } else 281af7ab184SArchie Cobbs cfg->bits = 0; 282af7ab184SArchie Cobbs 283af7ab184SArchie Cobbs /* Save return address so we can send reset-req's */ 284f3059f39SArchie Cobbs if (!isComp) 285069154d5SJulian Elischer priv->ctrlnode = NGI_RETADDR(item); 286af7ab184SArchie Cobbs 287af7ab184SArchie Cobbs /* Configuration is OK, reset to it */ 288af7ab184SArchie Cobbs d->cfg = *cfg; 289af7ab184SArchie Cobbs 290af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION 291af7ab184SArchie Cobbs /* Initialize state buffers for compression */ 292af7ab184SArchie Cobbs if (d->history != NULL) { 2931ede983cSDag-Erling Smørgrav free(d->history, M_NETGRAPH_MPPC); 294af7ab184SArchie Cobbs d->history = NULL; 295af7ab184SArchie Cobbs } 296af7ab184SArchie Cobbs if ((cfg->bits & MPPC_BIT) != 0) { 297e11e3f18SDag-Erling Smørgrav d->history = malloc(isComp ? 298e11e3f18SDag-Erling Smørgrav MPPC_SizeOfCompressionHistory() : 299af7ab184SArchie Cobbs MPPC_SizeOfDecompressionHistory(), 3009c8c302fSJulian Elischer M_NETGRAPH_MPPC, M_NOWAIT); 301af7ab184SArchie Cobbs if (d->history == NULL) 302af7ab184SArchie Cobbs ERROUT(ENOMEM); 303af7ab184SArchie Cobbs if (isComp) 304af7ab184SArchie Cobbs MPPC_InitCompressionHistory(d->history); 305af7ab184SArchie Cobbs else { 306af7ab184SArchie Cobbs MPPC_InitDecompressionHistory( 307af7ab184SArchie Cobbs d->history); 308af7ab184SArchie Cobbs } 309af7ab184SArchie Cobbs } 310af7ab184SArchie Cobbs #endif 311af7ab184SArchie Cobbs 312af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION 313af7ab184SArchie Cobbs /* Generate initial session keys for encryption */ 314af7ab184SArchie Cobbs if ((cfg->bits & MPPE_BITS) != 0) { 315af7ab184SArchie Cobbs const int keylen = KEYLEN(cfg->bits); 316af7ab184SArchie Cobbs 317af7ab184SArchie Cobbs bcopy(cfg->startkey, d->key, keylen); 318af7ab184SArchie Cobbs ng_mppc_getkey(cfg->startkey, d->key, keylen); 31934fd2381SArchie Cobbs if ((cfg->bits & MPPE_40) != 0) 32034fd2381SArchie Cobbs bcopy(&ng_mppe_weakenkey, d->key, 3); 32134fd2381SArchie Cobbs else if ((cfg->bits & MPPE_56) != 0) 32234fd2381SArchie Cobbs bcopy(&ng_mppe_weakenkey, d->key, 1); 323af7ab184SArchie Cobbs rc4_init(&d->rc4, d->key, keylen); 324af7ab184SArchie Cobbs } 325af7ab184SArchie Cobbs #endif 326af7ab184SArchie Cobbs 327af7ab184SArchie Cobbs /* Initialize other state */ 328af7ab184SArchie Cobbs d->cc = 0; 329af7ab184SArchie Cobbs d->flushed = 0; 330af7ab184SArchie Cobbs break; 331af7ab184SArchie Cobbs } 332af7ab184SArchie Cobbs 333af7ab184SArchie Cobbs case NGM_MPPC_RESETREQ: 334af7ab184SArchie Cobbs ng_mppc_reset_req(node); 335af7ab184SArchie Cobbs break; 336af7ab184SArchie Cobbs 337af7ab184SArchie Cobbs default: 338af7ab184SArchie Cobbs error = EINVAL; 339af7ab184SArchie Cobbs break; 340af7ab184SArchie Cobbs } 341af7ab184SArchie Cobbs break; 342af7ab184SArchie Cobbs default: 343af7ab184SArchie Cobbs error = EINVAL; 344af7ab184SArchie Cobbs break; 345af7ab184SArchie Cobbs } 346af7ab184SArchie Cobbs done: 347069154d5SJulian Elischer NG_RESPOND_MSG(error, node, item, resp); 348069154d5SJulian Elischer NG_FREE_MSG(msg); 349af7ab184SArchie Cobbs return (error); 350af7ab184SArchie Cobbs } 351af7ab184SArchie Cobbs 352af7ab184SArchie Cobbs /* 353af7ab184SArchie Cobbs * Receive incoming data on our hook. 354af7ab184SArchie Cobbs */ 355af7ab184SArchie Cobbs static int 356069154d5SJulian Elischer ng_mppc_rcvdata(hook_p hook, item_p item) 357af7ab184SArchie Cobbs { 35830400f03SJulian Elischer const node_p node = NG_HOOK_NODE(hook); 35930400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 360af7ab184SArchie Cobbs int error; 361069154d5SJulian Elischer struct mbuf *m; 362af7ab184SArchie Cobbs 363069154d5SJulian Elischer NGI_GET_M(item, m); 364af7ab184SArchie Cobbs /* Compress and/or encrypt */ 365af7ab184SArchie Cobbs if (hook == priv->xmit.hook) { 366af7ab184SArchie Cobbs if (!priv->xmit.cfg.enable) { 367069154d5SJulian Elischer NG_FREE_M(m); 368069154d5SJulian Elischer NG_FREE_ITEM(item); 369af7ab184SArchie Cobbs return (ENXIO); 370af7ab184SArchie Cobbs } 371ce52e8f4SAlexander Motin if ((error = ng_mppc_compress(node, &m)) != 0) { 372069154d5SJulian Elischer NG_FREE_ITEM(item); 373af7ab184SArchie Cobbs return(error); 374af7ab184SArchie Cobbs } 375ce52e8f4SAlexander Motin NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m); 376af7ab184SArchie Cobbs return (error); 377af7ab184SArchie Cobbs } 378af7ab184SArchie Cobbs 379af7ab184SArchie Cobbs /* Decompress and/or decrypt */ 380af7ab184SArchie Cobbs if (hook == priv->recv.hook) { 381af7ab184SArchie Cobbs if (!priv->recv.cfg.enable) { 382069154d5SJulian Elischer NG_FREE_M(m); 383069154d5SJulian Elischer NG_FREE_ITEM(item); 384af7ab184SArchie Cobbs return (ENXIO); 385af7ab184SArchie Cobbs } 386ce52e8f4SAlexander Motin if ((error = ng_mppc_decompress(node, &m)) != 0) { 387069154d5SJulian Elischer NG_FREE_ITEM(item); 388facfd889SArchie Cobbs if (error == EINVAL && priv->ctrlnode != 0) { 389af7ab184SArchie Cobbs struct ng_mesg *msg; 390af7ab184SArchie Cobbs 391af7ab184SArchie Cobbs /* Need to send a reset-request */ 392af7ab184SArchie Cobbs NG_MKMESSAGE(msg, NGM_MPPC_COOKIE, 393af7ab184SArchie Cobbs NGM_MPPC_RESETREQ, 0, M_NOWAIT); 394af7ab184SArchie Cobbs if (msg == NULL) 395af7ab184SArchie Cobbs return (error); 396069154d5SJulian Elischer NG_SEND_MSG_ID(error, node, msg, 397facfd889SArchie Cobbs priv->ctrlnode, 0); 398af7ab184SArchie Cobbs } 399af7ab184SArchie Cobbs return (error); 400af7ab184SArchie Cobbs } 401ce52e8f4SAlexander Motin NG_FWD_NEW_DATA(error, item, priv->recv.hook, m); 402af7ab184SArchie Cobbs return (error); 403af7ab184SArchie Cobbs } 404af7ab184SArchie Cobbs 405af7ab184SArchie Cobbs /* Oops */ 4066e551fb6SDavid E. O'Brien panic("%s: unknown hook", __func__); 407b40ce416SJulian Elischer #ifdef RESTARTABLE_PANICS 408b40ce416SJulian Elischer return (EINVAL); 409b40ce416SJulian Elischer #endif 410af7ab184SArchie Cobbs } 411af7ab184SArchie Cobbs 412af7ab184SArchie Cobbs /* 413af7ab184SArchie Cobbs * Destroy node 414af7ab184SArchie Cobbs */ 415af7ab184SArchie Cobbs static int 416069154d5SJulian Elischer ng_mppc_shutdown(node_p node) 417af7ab184SArchie Cobbs { 41830400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 419af7ab184SArchie Cobbs 420af7ab184SArchie Cobbs /* Take down netgraph node */ 421af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION 422af7ab184SArchie Cobbs if (priv->xmit.history != NULL) 4231ede983cSDag-Erling Smørgrav free(priv->xmit.history, M_NETGRAPH_MPPC); 424af7ab184SArchie Cobbs if (priv->recv.history != NULL) 4251ede983cSDag-Erling Smørgrav free(priv->recv.history, M_NETGRAPH_MPPC); 426af7ab184SArchie Cobbs #endif 427af7ab184SArchie Cobbs bzero(priv, sizeof(*priv)); 4281ede983cSDag-Erling Smørgrav free(priv, M_NETGRAPH_MPPC); 42930400f03SJulian Elischer NG_NODE_SET_PRIVATE(node, NULL); 43030400f03SJulian Elischer NG_NODE_UNREF(node); /* let the node escape */ 431af7ab184SArchie Cobbs return (0); 432af7ab184SArchie Cobbs } 433af7ab184SArchie Cobbs 434af7ab184SArchie Cobbs /* 435af7ab184SArchie Cobbs * Hook disconnection 436af7ab184SArchie Cobbs */ 437af7ab184SArchie Cobbs static int 438af7ab184SArchie Cobbs ng_mppc_disconnect(hook_p hook) 439af7ab184SArchie Cobbs { 44030400f03SJulian Elischer const node_p node = NG_HOOK_NODE(hook); 44130400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 442af7ab184SArchie Cobbs 443af7ab184SArchie Cobbs /* Zero out hook pointer */ 444af7ab184SArchie Cobbs if (hook == priv->xmit.hook) 445af7ab184SArchie Cobbs priv->xmit.hook = NULL; 446af7ab184SArchie Cobbs if (hook == priv->recv.hook) 447af7ab184SArchie Cobbs priv->recv.hook = NULL; 448af7ab184SArchie Cobbs 449af7ab184SArchie Cobbs /* Go away if no longer connected */ 45030400f03SJulian Elischer if ((NG_NODE_NUMHOOKS(node) == 0) 45130400f03SJulian Elischer && NG_NODE_IS_VALID(node)) 452069154d5SJulian Elischer ng_rmnode_self(node); 453af7ab184SArchie Cobbs return (0); 454af7ab184SArchie Cobbs } 455af7ab184SArchie Cobbs 456af7ab184SArchie Cobbs /************************************************************************ 457af7ab184SArchie Cobbs HELPER STUFF 458af7ab184SArchie Cobbs ************************************************************************/ 459af7ab184SArchie Cobbs 460af7ab184SArchie Cobbs /* 461af7ab184SArchie Cobbs * Compress/encrypt a packet and put the result in a new mbuf at *resultp. 462af7ab184SArchie Cobbs * The original mbuf is not free'd. 463af7ab184SArchie Cobbs */ 464af7ab184SArchie Cobbs static int 465ce52e8f4SAlexander Motin ng_mppc_compress(node_p node, struct mbuf **datap) 466af7ab184SArchie Cobbs { 46730400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 468af7ab184SArchie Cobbs struct ng_mppc_dir *const d = &priv->xmit; 469af7ab184SArchie Cobbs u_int16_t header; 470ce52e8f4SAlexander Motin struct mbuf *m = *datap; 471af7ab184SArchie Cobbs 472e4651e05SAlexander Motin /* We must own the mbuf chain exclusively to modify it. */ 473e4651e05SAlexander Motin m = m_unshare(m, M_DONTWAIT); 474e4651e05SAlexander Motin if (m == NULL) 475e4651e05SAlexander Motin return (ENOMEM); 476e4651e05SAlexander Motin 477af7ab184SArchie Cobbs /* Initialize */ 478af7ab184SArchie Cobbs header = d->cc; 479adecf751SAlexander Motin 480adecf751SAlexander Motin /* Always set the flushed bit in stateless mode */ 481adecf751SAlexander Motin if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) { 482af7ab184SArchie Cobbs header |= MPPC_FLAG_FLUSHED; 483af7ab184SArchie Cobbs d->flushed = 0; 484af7ab184SArchie Cobbs } 485af7ab184SArchie Cobbs 486ce52e8f4SAlexander Motin /* Compress packet (if compression enabled) */ 487af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION 488af7ab184SArchie Cobbs if ((d->cfg.bits & MPPC_BIT) != 0) { 489af7ab184SArchie Cobbs u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS; 490ce52e8f4SAlexander Motin u_char *inbuf, *outbuf; 49167898a23SAlexander Motin int outlen, inlen, ina; 492af7ab184SArchie Cobbs u_char *source, *dest; 493af7ab184SArchie Cobbs u_long sourceCnt, destCnt; 494af7ab184SArchie Cobbs int rtn; 495af7ab184SArchie Cobbs 496ce52e8f4SAlexander Motin /* Work with contiguous regions of memory. */ 497ce52e8f4SAlexander Motin inlen = m->m_pkthdr.len; 49867898a23SAlexander Motin if (m->m_next == NULL) { 49967898a23SAlexander Motin inbuf = mtod(m, u_char *); 50067898a23SAlexander Motin ina = 0; 50167898a23SAlexander Motin } else { 502ce52e8f4SAlexander Motin inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT); 50311d1cadeSAlexander Motin if (inbuf == NULL) 50411d1cadeSAlexander Motin goto err1; 505ce52e8f4SAlexander Motin m_copydata(m, 0, inlen, (caddr_t)inbuf); 50667898a23SAlexander Motin ina = 1; 50767898a23SAlexander Motin } 508ce52e8f4SAlexander Motin 509ce52e8f4SAlexander Motin outlen = MPPC_MAX_BLOWUP(inlen); 510ce52e8f4SAlexander Motin outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT); 511ce52e8f4SAlexander Motin if (outbuf == NULL) { 51267898a23SAlexander Motin if (ina) 513ce52e8f4SAlexander Motin free(inbuf, M_NETGRAPH_MPPC); 51411d1cadeSAlexander Motin err1: 51511d1cadeSAlexander Motin m_freem(m); 51611d1cadeSAlexander Motin MPPC_InitCompressionHistory(d->history); 51711d1cadeSAlexander Motin d->flushed = 1; 518ce52e8f4SAlexander Motin return (ENOMEM); 519ce52e8f4SAlexander Motin } 520ce52e8f4SAlexander Motin 521af7ab184SArchie Cobbs /* Prepare to compress */ 522af7ab184SArchie Cobbs source = inbuf; 523af7ab184SArchie Cobbs sourceCnt = inlen; 524ce52e8f4SAlexander Motin dest = outbuf; 525ce52e8f4SAlexander Motin destCnt = outlen; 526af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_STATELESS) == 0) 527af7ab184SArchie Cobbs flags |= MPPC_SAVE_HISTORY; 528af7ab184SArchie Cobbs 529af7ab184SArchie Cobbs /* Compress */ 530af7ab184SArchie Cobbs rtn = MPPC_Compress(&source, &dest, &sourceCnt, 531af7ab184SArchie Cobbs &destCnt, d->history, flags, 0); 532af7ab184SArchie Cobbs 533af7ab184SArchie Cobbs /* Check return value */ 5346e551fb6SDavid E. O'Brien KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); 535af7ab184SArchie Cobbs if ((rtn & MPPC_EXPANDED) == 0 536af7ab184SArchie Cobbs && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) { 537af7ab184SArchie Cobbs outlen -= destCnt; 538af7ab184SArchie Cobbs header |= MPPC_FLAG_COMPRESSED; 539af7ab184SArchie Cobbs if ((rtn & MPPC_RESTART_HISTORY) != 0) 540af7ab184SArchie Cobbs header |= MPPC_FLAG_RESTART; 541ce52e8f4SAlexander Motin 542ce52e8f4SAlexander Motin /* Replace m by the compresed one. */ 543e4651e05SAlexander Motin m_copyback(m, 0, outlen, (caddr_t)outbuf); 544e4651e05SAlexander Motin if (m->m_pkthdr.len < outlen) { 545ce52e8f4SAlexander Motin m_freem(m); 546e4651e05SAlexander Motin m = NULL; 547e4651e05SAlexander Motin } else if (outlen < m->m_pkthdr.len) 548e4651e05SAlexander Motin m_adj(m, outlen - m->m_pkthdr.len); 549af7ab184SArchie Cobbs } 550af7ab184SArchie Cobbs d->flushed = (rtn & MPPC_EXPANDED) != 0 551af7ab184SArchie Cobbs || (flags & MPPC_SAVE_HISTORY) == 0; 552ce52e8f4SAlexander Motin 55367898a23SAlexander Motin if (ina) 554ce52e8f4SAlexander Motin free(inbuf, M_NETGRAPH_MPPC); 555ce52e8f4SAlexander Motin free(outbuf, M_NETGRAPH_MPPC); 556ce52e8f4SAlexander Motin 557e4651e05SAlexander Motin /* Check mbuf chain reload result. */ 55811d1cadeSAlexander Motin if (m == NULL) { 55911d1cadeSAlexander Motin if (!d->flushed) { 56011d1cadeSAlexander Motin MPPC_InitCompressionHistory(d->history); 56111d1cadeSAlexander Motin d->flushed = 1; 56211d1cadeSAlexander Motin } 563ce52e8f4SAlexander Motin return (ENOMEM); 564af7ab184SArchie Cobbs } 56511d1cadeSAlexander Motin } 566af7ab184SArchie Cobbs #endif 567af7ab184SArchie Cobbs 568af7ab184SArchie Cobbs /* Now encrypt packet (if encryption enabled) */ 569af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION 570af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_BITS) != 0) { 571ce52e8f4SAlexander Motin struct mbuf *m1; 572af7ab184SArchie Cobbs 5736370fd6bSAlexander Motin /* Set header bits */ 574af7ab184SArchie Cobbs header |= MPPC_FLAG_ENCRYPTED; 575af7ab184SArchie Cobbs 576af7ab184SArchie Cobbs /* Update key if it's time */ 577af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_STATELESS) != 0 578af7ab184SArchie Cobbs || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) { 579af7ab184SArchie Cobbs ng_mppc_updatekey(d->cfg.bits, 580af7ab184SArchie Cobbs d->cfg.startkey, d->key, &d->rc4); 5816370fd6bSAlexander Motin } else if ((header & MPPC_FLAG_FLUSHED) != 0) { 5826370fd6bSAlexander Motin /* Need to reset key if we say we did 5836370fd6bSAlexander Motin and ng_mppc_updatekey wasn't called to do it also. */ 5846370fd6bSAlexander Motin rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 585af7ab184SArchie Cobbs } 586af7ab184SArchie Cobbs 587af7ab184SArchie Cobbs /* Encrypt packet */ 588ce52e8f4SAlexander Motin m1 = m; 589ce52e8f4SAlexander Motin while (m1) { 590ce52e8f4SAlexander Motin rc4_crypt(&d->rc4, mtod(m1, u_char *), 591ce52e8f4SAlexander Motin mtod(m1, u_char *), m1->m_len); 592ce52e8f4SAlexander Motin m1 = m1->m_next; 593ce52e8f4SAlexander Motin } 594af7ab184SArchie Cobbs } 595af7ab184SArchie Cobbs #endif 596af7ab184SArchie Cobbs 597755bc287SAlexander Motin /* Update coherency count for next time (12 bit arithmetic) */ 598755bc287SAlexander Motin MPPC_CCOUNT_INC(d->cc); 599af7ab184SArchie Cobbs 600af7ab184SArchie Cobbs /* Install header */ 601ce52e8f4SAlexander Motin M_PREPEND(m, MPPC_HDRLEN, M_DONTWAIT); 602ce52e8f4SAlexander Motin if (m != NULL) 60339228864SAlexander Motin be16enc(mtod(m, void *), header); 604af7ab184SArchie Cobbs 605ce52e8f4SAlexander Motin *datap = m; 606ce52e8f4SAlexander Motin return (*datap == NULL ? ENOBUFS : 0); 607af7ab184SArchie Cobbs } 608af7ab184SArchie Cobbs 609af7ab184SArchie Cobbs /* 610af7ab184SArchie Cobbs * Decompress/decrypt packet and put the result in a new mbuf at *resultp. 611af7ab184SArchie Cobbs * The original mbuf is not free'd. 612af7ab184SArchie Cobbs */ 613af7ab184SArchie Cobbs static int 614ce52e8f4SAlexander Motin ng_mppc_decompress(node_p node, struct mbuf **datap) 615af7ab184SArchie Cobbs { 61630400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 617af7ab184SArchie Cobbs struct ng_mppc_dir *const d = &priv->recv; 618f3059f39SArchie Cobbs u_int16_t header, cc; 619f3059f39SArchie Cobbs u_int numLost; 620ce52e8f4SAlexander Motin struct mbuf *m = *datap; 621af7ab184SArchie Cobbs 622e4651e05SAlexander Motin /* We must own the mbuf chain exclusively to modify it. */ 623e4651e05SAlexander Motin m = m_unshare(m, M_DONTWAIT); 624e4651e05SAlexander Motin if (m == NULL) 625e4651e05SAlexander Motin return (ENOMEM); 626e4651e05SAlexander Motin 627af7ab184SArchie Cobbs /* Pull off header */ 628ce52e8f4SAlexander Motin if (m->m_pkthdr.len < MPPC_HDRLEN) { 629ce52e8f4SAlexander Motin m_freem(m); 630af7ab184SArchie Cobbs return (EINVAL); 631ce52e8f4SAlexander Motin } 63239228864SAlexander Motin header = be16dec(mtod(m, void *)); 633af7ab184SArchie Cobbs cc = (header & MPPC_CCOUNT_MASK); 634ce52e8f4SAlexander Motin m_adj(m, MPPC_HDRLEN); 635af7ab184SArchie Cobbs 636f3059f39SArchie Cobbs /* Check for an unexpected jump in the sequence number */ 637af7ab184SArchie Cobbs numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK); 638af7ab184SArchie Cobbs 639af7ab184SArchie Cobbs /* If flushed bit set, we can always handle packet */ 640af7ab184SArchie Cobbs if ((header & MPPC_FLAG_FLUSHED) != 0) { 641af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION 642af7ab184SArchie Cobbs if (d->history != NULL) 643af7ab184SArchie Cobbs MPPC_InitDecompressionHistory(d->history); 644af7ab184SArchie Cobbs #endif 645af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION 646af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_BITS) != 0) { 647f3059f39SArchie Cobbs u_int rekey; 648af7ab184SArchie Cobbs 649f3059f39SArchie Cobbs /* How many times are we going to have to re-key? */ 650f3059f39SArchie Cobbs rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ? 651f3059f39SArchie Cobbs numLost : (numLost / (MPPE_UPDATE_MASK + 1)); 652f3059f39SArchie Cobbs if (rekey > MPPE_MAX_REKEY) { 653f3059f39SArchie Cobbs log(LOG_ERR, "%s: too many (%d) packets" 654f3059f39SArchie Cobbs " dropped, disabling node %p!", 655f3059f39SArchie Cobbs __func__, numLost, node); 656f3059f39SArchie Cobbs priv->recv.cfg.enable = 0; 657f3059f39SArchie Cobbs goto failed; 658f3059f39SArchie Cobbs } 659f3059f39SArchie Cobbs 660f3059f39SArchie Cobbs /* Re-key as necessary to catch up to peer */ 661af7ab184SArchie Cobbs while (d->cc != cc) { 662f3059f39SArchie Cobbs if ((d->cfg.bits & MPPE_STATELESS) != 0 663af7ab184SArchie Cobbs || (d->cc & MPPE_UPDATE_MASK) 664af7ab184SArchie Cobbs == MPPE_UPDATE_FLAG) { 665af7ab184SArchie Cobbs ng_mppc_updatekey(d->cfg.bits, 666af7ab184SArchie Cobbs d->cfg.startkey, d->key, &d->rc4); 667af7ab184SArchie Cobbs } 668755bc287SAlexander Motin MPPC_CCOUNT_INC(d->cc); 669af7ab184SArchie Cobbs } 670af7ab184SArchie Cobbs 671af7ab184SArchie Cobbs /* Reset key (except in stateless mode, see below) */ 672af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_STATELESS) == 0) 673af7ab184SArchie Cobbs rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 674af7ab184SArchie Cobbs } 675af7ab184SArchie Cobbs #endif 676af7ab184SArchie Cobbs d->cc = cc; /* skip over lost seq numbers */ 677af7ab184SArchie Cobbs numLost = 0; /* act like no packets were lost */ 678af7ab184SArchie Cobbs } 679af7ab184SArchie Cobbs 680af7ab184SArchie Cobbs /* Can't decode non-sequential packets without a flushed bit */ 681af7ab184SArchie Cobbs if (numLost != 0) 682af7ab184SArchie Cobbs goto failed; 683af7ab184SArchie Cobbs 684af7ab184SArchie Cobbs /* Decrypt packet */ 685af7ab184SArchie Cobbs if ((header & MPPC_FLAG_ENCRYPTED) != 0) { 686ce52e8f4SAlexander Motin #ifdef NETGRAPH_MPPC_ENCRYPTION 687ce52e8f4SAlexander Motin struct mbuf *m1; 688ce52e8f4SAlexander Motin #endif 689af7ab184SArchie Cobbs 690af7ab184SArchie Cobbs /* Are we not expecting encryption? */ 691af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_BITS) == 0) { 692af7ab184SArchie Cobbs log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 6936e551fb6SDavid E. O'Brien __func__, "encrypted"); 694af7ab184SArchie Cobbs goto failed; 695af7ab184SArchie Cobbs } 696af7ab184SArchie Cobbs 697af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION 698af7ab184SArchie Cobbs /* Update key if it's time (always in stateless mode) */ 699af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_STATELESS) != 0 700af7ab184SArchie Cobbs || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) { 701af7ab184SArchie Cobbs ng_mppc_updatekey(d->cfg.bits, 702af7ab184SArchie Cobbs d->cfg.startkey, d->key, &d->rc4); 703af7ab184SArchie Cobbs } 704af7ab184SArchie Cobbs 705af7ab184SArchie Cobbs /* Decrypt packet */ 706ce52e8f4SAlexander Motin m1 = m; 707ce52e8f4SAlexander Motin while (m1 != NULL) { 708ce52e8f4SAlexander Motin rc4_crypt(&d->rc4, mtod(m1, u_char *), 709ce52e8f4SAlexander Motin mtod(m1, u_char *), m1->m_len); 710ce52e8f4SAlexander Motin m1 = m1->m_next; 711ce52e8f4SAlexander Motin } 712af7ab184SArchie Cobbs #endif 713af7ab184SArchie Cobbs } else { 714af7ab184SArchie Cobbs 715af7ab184SArchie Cobbs /* Are we expecting encryption? */ 716af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_BITS) != 0) { 717af7ab184SArchie Cobbs log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 7186e551fb6SDavid E. O'Brien __func__, "unencrypted"); 719af7ab184SArchie Cobbs goto failed; 720af7ab184SArchie Cobbs } 721af7ab184SArchie Cobbs } 722af7ab184SArchie Cobbs 723af7ab184SArchie Cobbs /* Update coherency count for next time (12 bit arithmetic) */ 724755bc287SAlexander Motin MPPC_CCOUNT_INC(d->cc); 725af7ab184SArchie Cobbs 726af7ab184SArchie Cobbs /* Check for unexpected compressed packet */ 727af7ab184SArchie Cobbs if ((header & MPPC_FLAG_COMPRESSED) != 0 728af7ab184SArchie Cobbs && (d->cfg.bits & MPPC_BIT) == 0) { 729af7ab184SArchie Cobbs log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 7306e551fb6SDavid E. O'Brien __func__, "compressed"); 731af7ab184SArchie Cobbs failed: 732ce52e8f4SAlexander Motin m_freem(m); 733af7ab184SArchie Cobbs return (EINVAL); 734af7ab184SArchie Cobbs } 735af7ab184SArchie Cobbs 736af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION 737af7ab184SArchie Cobbs /* Decompress packet */ 738af7ab184SArchie Cobbs if ((header & MPPC_FLAG_COMPRESSED) != 0) { 739af7ab184SArchie Cobbs int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS; 74067898a23SAlexander Motin u_char *inbuf, *outbuf; 74167898a23SAlexander Motin int inlen, outlen, ina; 74267898a23SAlexander Motin u_char *source, *dest; 743af7ab184SArchie Cobbs u_long sourceCnt, destCnt; 74467898a23SAlexander Motin int rtn; 745ce52e8f4SAlexander Motin 746ce52e8f4SAlexander Motin /* Copy payload into a contiguous region of memory. */ 74767898a23SAlexander Motin inlen = m->m_pkthdr.len; 74867898a23SAlexander Motin if (m->m_next == NULL) { 74967898a23SAlexander Motin inbuf = mtod(m, u_char *); 75067898a23SAlexander Motin ina = 0; 75167898a23SAlexander Motin } else { 75267898a23SAlexander Motin inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT); 75367898a23SAlexander Motin if (inbuf == NULL) { 754ce52e8f4SAlexander Motin m_freem(m); 755ce52e8f4SAlexander Motin return (ENOMEM); 756ce52e8f4SAlexander Motin } 75767898a23SAlexander Motin m_copydata(m, 0, inlen, (caddr_t)inbuf); 75867898a23SAlexander Motin ina = 1; 75967898a23SAlexander Motin } 760af7ab184SArchie Cobbs 761af7ab184SArchie Cobbs /* Allocate a buffer for decompressed data */ 76267898a23SAlexander Motin outbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY, 763ce52e8f4SAlexander Motin M_NETGRAPH_MPPC, M_NOWAIT); 76467898a23SAlexander Motin if (outbuf == NULL) { 765ce52e8f4SAlexander Motin m_freem(m); 76667898a23SAlexander Motin if (ina) 76767898a23SAlexander Motin free(inbuf, M_NETGRAPH_MPPC); 768af7ab184SArchie Cobbs return (ENOMEM); 769af7ab184SArchie Cobbs } 77067898a23SAlexander Motin outlen = MPPC_DECOMP_BUFSIZE; 771af7ab184SArchie Cobbs 772af7ab184SArchie Cobbs /* Prepare to decompress */ 77367898a23SAlexander Motin source = inbuf; 77467898a23SAlexander Motin sourceCnt = inlen; 77567898a23SAlexander Motin dest = outbuf; 77667898a23SAlexander Motin destCnt = outlen; 777af7ab184SArchie Cobbs if ((header & MPPC_FLAG_RESTART) != 0) 778af7ab184SArchie Cobbs flags |= MPPC_RESTART_HISTORY; 779af7ab184SArchie Cobbs 780af7ab184SArchie Cobbs /* Decompress */ 781af7ab184SArchie Cobbs rtn = MPPC_Decompress(&source, &dest, 782af7ab184SArchie Cobbs &sourceCnt, &destCnt, d->history, flags); 783af7ab184SArchie Cobbs 784af7ab184SArchie Cobbs /* Check return value */ 7856e551fb6SDavid E. O'Brien KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); 786af7ab184SArchie Cobbs if ((rtn & MPPC_DEST_EXHAUSTED) != 0 787af7ab184SArchie Cobbs || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) { 788af7ab184SArchie Cobbs log(LOG_ERR, "%s: decomp returned 0x%x", 7896e551fb6SDavid E. O'Brien __func__, rtn); 79067898a23SAlexander Motin if (ina) 79167898a23SAlexander Motin free(inbuf, M_NETGRAPH_MPPC); 79267898a23SAlexander Motin free(outbuf, M_NETGRAPH_MPPC); 793af7ab184SArchie Cobbs goto failed; 794af7ab184SArchie Cobbs } 795af7ab184SArchie Cobbs 796af7ab184SArchie Cobbs /* Replace compressed data with decompressed data */ 79767898a23SAlexander Motin if (ina) 79867898a23SAlexander Motin free(inbuf, M_NETGRAPH_MPPC); 79967898a23SAlexander Motin outlen -= destCnt; 800ce52e8f4SAlexander Motin 80167898a23SAlexander Motin m_copyback(m, 0, outlen, (caddr_t)outbuf); 80267898a23SAlexander Motin if (m->m_pkthdr.len < outlen) { 803ce52e8f4SAlexander Motin m_freem(m); 804e4651e05SAlexander Motin m = NULL; 80567898a23SAlexander Motin } else if (outlen < m->m_pkthdr.len) 80667898a23SAlexander Motin m_adj(m, outlen - m->m_pkthdr.len); 80767898a23SAlexander Motin free(outbuf, M_NETGRAPH_MPPC); 808af7ab184SArchie Cobbs } 809af7ab184SArchie Cobbs #endif 810af7ab184SArchie Cobbs 811af7ab184SArchie Cobbs /* Return result in an mbuf */ 812ce52e8f4SAlexander Motin *datap = m; 813ce52e8f4SAlexander Motin return (*datap == NULL ? ENOBUFS : 0); 814af7ab184SArchie Cobbs } 815af7ab184SArchie Cobbs 816af7ab184SArchie Cobbs /* 817af7ab184SArchie Cobbs * The peer has sent us a CCP ResetRequest, so reset our transmit state. 818af7ab184SArchie Cobbs */ 819af7ab184SArchie Cobbs static void 820af7ab184SArchie Cobbs ng_mppc_reset_req(node_p node) 821af7ab184SArchie Cobbs { 82230400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 823af7ab184SArchie Cobbs struct ng_mppc_dir *const d = &priv->xmit; 824af7ab184SArchie Cobbs 825af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION 826af7ab184SArchie Cobbs if (d->history != NULL) 827af7ab184SArchie Cobbs MPPC_InitCompressionHistory(d->history); 828af7ab184SArchie Cobbs #endif 829af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION 830af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_STATELESS) == 0) 831af7ab184SArchie Cobbs rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 832af7ab184SArchie Cobbs #endif 833af7ab184SArchie Cobbs d->flushed = 1; 834af7ab184SArchie Cobbs } 835af7ab184SArchie Cobbs 83606c51e6eSAlexander Motin #ifdef NETGRAPH_MPPC_ENCRYPTION 837af7ab184SArchie Cobbs /* 838af7ab184SArchie Cobbs * Generate a new encryption key 839af7ab184SArchie Cobbs */ 840af7ab184SArchie Cobbs static void 841af7ab184SArchie Cobbs ng_mppc_getkey(const u_char *h, u_char *h2, int len) 842af7ab184SArchie Cobbs { 843b3d298b9SAlexander Motin static const u_char pad1[40] = 844b3d298b9SAlexander Motin { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 845b3d298b9SAlexander Motin 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 846b3d298b9SAlexander Motin 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 847b3d298b9SAlexander Motin 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 848b3d298b9SAlexander Motin static const u_char pad2[40] = 849b3d298b9SAlexander Motin { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 850b3d298b9SAlexander Motin 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 851b3d298b9SAlexander Motin 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 852b3d298b9SAlexander Motin 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2 }; 853af7ab184SArchie Cobbs u_char hash[20]; 854af7ab184SArchie Cobbs SHA1_CTX c; 855af7ab184SArchie Cobbs 856af7ab184SArchie Cobbs SHA1Init(&c); 857af7ab184SArchie Cobbs SHA1Update(&c, h, len); 858592009a3SAlexander Motin SHA1Update(&c, pad1, sizeof(pad1)); 859af7ab184SArchie Cobbs SHA1Update(&c, h2, len); 860af7ab184SArchie Cobbs SHA1Update(&c, pad2, sizeof(pad2)); 861af7ab184SArchie Cobbs SHA1Final(hash, &c); 862af7ab184SArchie Cobbs bcopy(hash, h2, len); 863af7ab184SArchie Cobbs } 864af7ab184SArchie Cobbs 865af7ab184SArchie Cobbs /* 866af7ab184SArchie Cobbs * Update the encryption key 867af7ab184SArchie Cobbs */ 868af7ab184SArchie Cobbs static void 869af7ab184SArchie Cobbs ng_mppc_updatekey(u_int32_t bits, 870af7ab184SArchie Cobbs u_char *key0, u_char *key, struct rc4_state *rc4) 871af7ab184SArchie Cobbs { 872af7ab184SArchie Cobbs const int keylen = KEYLEN(bits); 873af7ab184SArchie Cobbs 874af7ab184SArchie Cobbs ng_mppc_getkey(key0, key, keylen); 875af7ab184SArchie Cobbs rc4_init(rc4, key, keylen); 876af7ab184SArchie Cobbs rc4_crypt(rc4, key, key, keylen); 87734fd2381SArchie Cobbs if ((bits & MPPE_40) != 0) 87834fd2381SArchie Cobbs bcopy(&ng_mppe_weakenkey, key, 3); 87934fd2381SArchie Cobbs else if ((bits & MPPE_56) != 0) 88034fd2381SArchie Cobbs bcopy(&ng_mppe_weakenkey, key, 1); 881af7ab184SArchie Cobbs rc4_init(rc4, key, keylen); 882af7ab184SArchie Cobbs } 88306c51e6eSAlexander Motin #endif 884af7ab184SArchie Cobbs 885