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> 58ee652839SAlexander Motin #include <sys/sysctl.h> 59af7ab184SArchie Cobbs #include <sys/syslog.h> 60af7ab184SArchie Cobbs 61af7ab184SArchie Cobbs #include <netgraph/ng_message.h> 62af7ab184SArchie Cobbs #include <netgraph/netgraph.h> 63af7ab184SArchie Cobbs #include <netgraph/ng_mppc.h> 64af7ab184SArchie Cobbs 65af7ab184SArchie Cobbs #include "opt_netgraph.h" 66af7ab184SArchie Cobbs 67af7ab184SArchie Cobbs #if !defined(NETGRAPH_MPPC_COMPRESSION) && !defined(NETGRAPH_MPPC_ENCRYPTION) 6810d645b7SYaroslav Tykhiy #ifdef KLD_MODULE 6910d645b7SYaroslav Tykhiy /* XXX NETGRAPH_MPPC_COMPRESSION isn't functional yet */ 7010d645b7SYaroslav Tykhiy #define NETGRAPH_MPPC_ENCRYPTION 7110d645b7SYaroslav Tykhiy #else 7210d645b7SYaroslav Tykhiy /* This case is indicative of an error in sys/conf files */ 73af7ab184SArchie Cobbs #error Need either NETGRAPH_MPPC_COMPRESSION or NETGRAPH_MPPC_ENCRYPTION 74af7ab184SArchie Cobbs #endif 7510d645b7SYaroslav Tykhiy #endif 76af7ab184SArchie Cobbs 779c8c302fSJulian Elischer #ifdef NG_SEPARATE_MALLOC 78d745c852SEd Schouten static MALLOC_DEFINE(M_NETGRAPH_MPPC, "netgraph_mppc", "netgraph mppc node"); 799c8c302fSJulian Elischer #else 809c8c302fSJulian Elischer #define M_NETGRAPH_MPPC M_NETGRAPH 819c8c302fSJulian Elischer #endif 829c8c302fSJulian Elischer 83af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION 84af7ab184SArchie Cobbs /* XXX this file doesn't exist yet, but hopefully someday it will... */ 85af7ab184SArchie Cobbs #include <net/mppc.h> 86af7ab184SArchie Cobbs #endif 87af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION 88af7ab184SArchie Cobbs #include <crypto/rc4/rc4.h> 89af7ab184SArchie Cobbs #endif 90af7ab184SArchie Cobbs #include <crypto/sha1.h> 91af7ab184SArchie Cobbs 92af7ab184SArchie Cobbs /* Decompression blowup */ 93af7ab184SArchie Cobbs #define MPPC_DECOMP_BUFSIZE 8092 /* allocate buffer this big */ 94af7ab184SArchie Cobbs #define MPPC_DECOMP_SAFETY 100 /* plus this much margin */ 95af7ab184SArchie Cobbs 96af7ab184SArchie Cobbs /* MPPC/MPPE header length */ 97af7ab184SArchie Cobbs #define MPPC_HDRLEN 2 98af7ab184SArchie Cobbs 99af7ab184SArchie Cobbs /* Key length */ 100af7ab184SArchie Cobbs #define KEYLEN(b) (((b) & MPPE_128) ? 16 : 8) 101af7ab184SArchie Cobbs 1025372c30bSGleb Smirnoff /* 1035372c30bSGleb Smirnoff * When packets are lost with MPPE, we may have to re-key arbitrarily 1045372c30bSGleb Smirnoff * many times to 'catch up' to the new jumped-ahead sequence number. 1055372c30bSGleb Smirnoff * Since this can be expensive, we pose a limit on how many re-keyings 1065372c30bSGleb Smirnoff * we will do at one time to avoid a possible D.O.S. vulnerability. 1075372c30bSGleb Smirnoff * This should instead be a configurable parameter. 1085372c30bSGleb Smirnoff */ 1095372c30bSGleb Smirnoff #define MPPE_MAX_REKEY 1000 1105372c30bSGleb Smirnoff 111ee652839SAlexander Motin SYSCTL_NODE(_net_graph, OID_AUTO, mppe, CTLFLAG_RW, 0, "MPPE"); 112ee652839SAlexander Motin 113ee652839SAlexander Motin static int mppe_block_on_max_rekey = 0; 114*af3b2549SHans Petter Selasky SYSCTL_INT(_net_graph_mppe, OID_AUTO, block_on_max_rekey, CTLFLAG_RWTUN, 115ee652839SAlexander Motin &mppe_block_on_max_rekey, 0, "Block node on max MPPE key re-calculations"); 116ee652839SAlexander Motin 117ee652839SAlexander Motin static int mppe_log_max_rekey = 1; 118*af3b2549SHans Petter Selasky SYSCTL_INT(_net_graph_mppe, OID_AUTO, log_max_rekey, CTLFLAG_RWTUN, 119ee652839SAlexander Motin &mppe_log_max_rekey, 0, "Log max MPPE key re-calculations event"); 120ee652839SAlexander Motin 121ee652839SAlexander Motin static int mppe_max_rekey = MPPE_MAX_REKEY; 122*af3b2549SHans Petter Selasky SYSCTL_INT(_net_graph_mppe, OID_AUTO, max_rekey, CTLFLAG_RWTUN, 123ee652839SAlexander Motin &mppe_max_rekey, 0, "Maximum number of MPPE key re-calculations"); 124ee652839SAlexander Motin 125af7ab184SArchie Cobbs /* MPPC packet header bits */ 126af7ab184SArchie Cobbs #define MPPC_FLAG_FLUSHED 0x8000 /* xmitter reset state */ 127af7ab184SArchie Cobbs #define MPPC_FLAG_RESTART 0x4000 /* compress history restart */ 128af7ab184SArchie Cobbs #define MPPC_FLAG_COMPRESSED 0x2000 /* packet is compresed */ 129af7ab184SArchie Cobbs #define MPPC_FLAG_ENCRYPTED 0x1000 /* packet is encrypted */ 130af7ab184SArchie Cobbs #define MPPC_CCOUNT_MASK 0x0fff /* sequence number mask */ 131af7ab184SArchie Cobbs 132755bc287SAlexander Motin #define MPPC_CCOUNT_INC(d) ((d) = (((d) + 1) & MPPC_CCOUNT_MASK)) 133755bc287SAlexander Motin 134af7ab184SArchie Cobbs #define MPPE_UPDATE_MASK 0xff /* coherency count when we're */ 135af7ab184SArchie Cobbs #define MPPE_UPDATE_FLAG 0xff /* supposed to update key */ 136af7ab184SArchie Cobbs 137af7ab184SArchie Cobbs #define MPPC_COMP_OK 0x05 138af7ab184SArchie Cobbs #define MPPC_DECOMP_OK 0x05 139af7ab184SArchie Cobbs 140af7ab184SArchie Cobbs /* Per direction info */ 141af7ab184SArchie Cobbs struct ng_mppc_dir { 142af7ab184SArchie Cobbs struct ng_mppc_config cfg; /* configuration */ 143af7ab184SArchie Cobbs hook_p hook; /* netgraph hook */ 144af7ab184SArchie Cobbs u_int16_t cc:12; /* coherency count */ 145af7ab184SArchie Cobbs u_char flushed; /* clean history (xmit only) */ 146af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION 147af7ab184SArchie Cobbs u_char *history; /* compression history */ 148af7ab184SArchie Cobbs #endif 149af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION 150af7ab184SArchie Cobbs u_char key[MPPE_KEY_LEN]; /* session key */ 151af7ab184SArchie Cobbs struct rc4_state rc4; /* rc4 state */ 152af7ab184SArchie Cobbs #endif 153af7ab184SArchie Cobbs }; 154af7ab184SArchie Cobbs 155af7ab184SArchie Cobbs /* Node private data */ 156af7ab184SArchie Cobbs struct ng_mppc_private { 157af7ab184SArchie Cobbs struct ng_mppc_dir xmit; /* compress/encrypt config */ 158af7ab184SArchie Cobbs struct ng_mppc_dir recv; /* decompress/decrypt config */ 159069154d5SJulian Elischer ng_ID_t ctrlnode; /* path to controlling node */ 160af7ab184SArchie Cobbs }; 161af7ab184SArchie Cobbs typedef struct ng_mppc_private *priv_p; 162af7ab184SArchie Cobbs 163af7ab184SArchie Cobbs /* Netgraph node methods */ 164af7ab184SArchie Cobbs static ng_constructor_t ng_mppc_constructor; 165af7ab184SArchie Cobbs static ng_rcvmsg_t ng_mppc_rcvmsg; 166069154d5SJulian Elischer static ng_shutdown_t ng_mppc_shutdown; 167af7ab184SArchie Cobbs static ng_newhook_t ng_mppc_newhook; 168af7ab184SArchie Cobbs static ng_rcvdata_t ng_mppc_rcvdata; 169af7ab184SArchie Cobbs static ng_disconnect_t ng_mppc_disconnect; 170af7ab184SArchie Cobbs 171af7ab184SArchie Cobbs /* Helper functions */ 172af7ab184SArchie Cobbs static int ng_mppc_compress(node_p node, 173ce52e8f4SAlexander Motin struct mbuf **datap); 174af7ab184SArchie Cobbs static int ng_mppc_decompress(node_p node, 175ce52e8f4SAlexander Motin struct mbuf **datap); 17606c51e6eSAlexander Motin #ifdef NETGRAPH_MPPC_ENCRYPTION 177af7ab184SArchie Cobbs static void ng_mppc_getkey(const u_char *h, u_char *h2, int len); 178af7ab184SArchie Cobbs static void ng_mppc_updatekey(u_int32_t bits, 179af7ab184SArchie Cobbs u_char *key0, u_char *key, struct rc4_state *rc4); 18006c51e6eSAlexander Motin #endif 181af7ab184SArchie Cobbs static void ng_mppc_reset_req(node_p node); 182af7ab184SArchie Cobbs 183af7ab184SArchie Cobbs /* Node type descriptor */ 184af7ab184SArchie Cobbs static struct ng_type ng_mppc_typestruct = { 185f8aae777SJulian Elischer .version = NG_ABI_VERSION, 186f8aae777SJulian Elischer .name = NG_MPPC_NODE_TYPE, 187f8aae777SJulian Elischer .constructor = ng_mppc_constructor, 188f8aae777SJulian Elischer .rcvmsg = ng_mppc_rcvmsg, 189f8aae777SJulian Elischer .shutdown = ng_mppc_shutdown, 190f8aae777SJulian Elischer .newhook = ng_mppc_newhook, 191f8aae777SJulian Elischer .rcvdata = ng_mppc_rcvdata, 192f8aae777SJulian Elischer .disconnect = ng_mppc_disconnect, 193af7ab184SArchie Cobbs }; 194af7ab184SArchie Cobbs NETGRAPH_INIT(mppc, &ng_mppc_typestruct); 195af7ab184SArchie Cobbs 196233896e9SDoug Ambrisko #ifdef NETGRAPH_MPPC_ENCRYPTION 197233896e9SDoug Ambrisko /* Depend on separate rc4 module */ 198233896e9SDoug Ambrisko MODULE_DEPEND(ng_mppc, rc4, 1, 1, 1); 199233896e9SDoug Ambrisko #endif 200233896e9SDoug Ambrisko 20134fd2381SArchie Cobbs /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */ 202af7ab184SArchie Cobbs static const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e }; 203af7ab184SArchie Cobbs 204af7ab184SArchie Cobbs #define ERROUT(x) do { error = (x); goto done; } while (0) 205af7ab184SArchie Cobbs 206af7ab184SArchie Cobbs /************************************************************************ 207af7ab184SArchie Cobbs NETGRAPH NODE STUFF 208af7ab184SArchie Cobbs ************************************************************************/ 209af7ab184SArchie Cobbs 210af7ab184SArchie Cobbs /* 211af7ab184SArchie Cobbs * Node type constructor 212af7ab184SArchie Cobbs */ 213af7ab184SArchie Cobbs static int 214069154d5SJulian Elischer ng_mppc_constructor(node_p node) 215af7ab184SArchie Cobbs { 216af7ab184SArchie Cobbs priv_p priv; 217af7ab184SArchie Cobbs 218af7ab184SArchie Cobbs /* Allocate private structure */ 219674d86bfSGleb Smirnoff priv = malloc(sizeof(*priv), M_NETGRAPH_MPPC, M_WAITOK | M_ZERO); 220af7ab184SArchie Cobbs 22130400f03SJulian Elischer NG_NODE_SET_PRIVATE(node, priv); 222af7ab184SArchie Cobbs 2232f07580bSGleb Smirnoff /* This node is not thread safe. */ 2242f07580bSGleb Smirnoff NG_NODE_FORCE_WRITER(node); 2252f07580bSGleb Smirnoff 226af7ab184SArchie Cobbs /* Done */ 227af7ab184SArchie Cobbs return (0); 228af7ab184SArchie Cobbs } 229af7ab184SArchie Cobbs 230af7ab184SArchie Cobbs /* 231af7ab184SArchie Cobbs * Give our OK for a hook to be added 232af7ab184SArchie Cobbs */ 233af7ab184SArchie Cobbs static int 234af7ab184SArchie Cobbs ng_mppc_newhook(node_p node, hook_p hook, const char *name) 235af7ab184SArchie Cobbs { 23630400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 237af7ab184SArchie Cobbs hook_p *hookPtr; 238af7ab184SArchie Cobbs 239af7ab184SArchie Cobbs /* Check hook name */ 240af7ab184SArchie Cobbs if (strcmp(name, NG_MPPC_HOOK_COMP) == 0) 241af7ab184SArchie Cobbs hookPtr = &priv->xmit.hook; 242af7ab184SArchie Cobbs else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0) 243af7ab184SArchie Cobbs hookPtr = &priv->recv.hook; 244af7ab184SArchie Cobbs else 245af7ab184SArchie Cobbs return (EINVAL); 246af7ab184SArchie Cobbs 247af7ab184SArchie Cobbs /* See if already connected */ 248af7ab184SArchie Cobbs if (*hookPtr != NULL) 249af7ab184SArchie Cobbs return (EISCONN); 250af7ab184SArchie Cobbs 251af7ab184SArchie Cobbs /* OK */ 252af7ab184SArchie Cobbs *hookPtr = hook; 253af7ab184SArchie Cobbs return (0); 254af7ab184SArchie Cobbs } 255af7ab184SArchie Cobbs 256af7ab184SArchie Cobbs /* 257af7ab184SArchie Cobbs * Receive a control message 258af7ab184SArchie Cobbs */ 259af7ab184SArchie Cobbs static int 260069154d5SJulian Elischer ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook) 261af7ab184SArchie Cobbs { 26230400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 263af7ab184SArchie Cobbs struct ng_mesg *resp = NULL; 264af7ab184SArchie Cobbs int error = 0; 265069154d5SJulian Elischer struct ng_mesg *msg; 266af7ab184SArchie Cobbs 267069154d5SJulian Elischer NGI_GET_MSG(item, msg); 268af7ab184SArchie Cobbs switch (msg->header.typecookie) { 269af7ab184SArchie Cobbs case NGM_MPPC_COOKIE: 270af7ab184SArchie Cobbs switch (msg->header.cmd) { 271af7ab184SArchie Cobbs case NGM_MPPC_CONFIG_COMP: 272af7ab184SArchie Cobbs case NGM_MPPC_CONFIG_DECOMP: 273af7ab184SArchie Cobbs { 274af7ab184SArchie Cobbs struct ng_mppc_config *const cfg 275af7ab184SArchie Cobbs = (struct ng_mppc_config *)msg->data; 276af7ab184SArchie Cobbs const int isComp = 277af7ab184SArchie Cobbs msg->header.cmd == NGM_MPPC_CONFIG_COMP; 278af7ab184SArchie Cobbs struct ng_mppc_dir *const d = isComp ? 279af7ab184SArchie Cobbs &priv->xmit : &priv->recv; 280af7ab184SArchie Cobbs 281af7ab184SArchie Cobbs /* Check configuration */ 282af7ab184SArchie Cobbs if (msg->header.arglen != sizeof(*cfg)) 283af7ab184SArchie Cobbs ERROUT(EINVAL); 284af7ab184SArchie Cobbs if (cfg->enable) { 285af7ab184SArchie Cobbs if ((cfg->bits & ~MPPC_VALID_BITS) != 0) 286af7ab184SArchie Cobbs ERROUT(EINVAL); 287af7ab184SArchie Cobbs #ifndef NETGRAPH_MPPC_COMPRESSION 288af7ab184SArchie Cobbs if ((cfg->bits & MPPC_BIT) != 0) 289af7ab184SArchie Cobbs ERROUT(EPROTONOSUPPORT); 290af7ab184SArchie Cobbs #endif 291af7ab184SArchie Cobbs #ifndef NETGRAPH_MPPC_ENCRYPTION 292af7ab184SArchie Cobbs if ((cfg->bits & MPPE_BITS) != 0) 293af7ab184SArchie Cobbs ERROUT(EPROTONOSUPPORT); 294af7ab184SArchie Cobbs #endif 295af7ab184SArchie Cobbs } else 296af7ab184SArchie Cobbs cfg->bits = 0; 297af7ab184SArchie Cobbs 298af7ab184SArchie Cobbs /* Save return address so we can send reset-req's */ 299f3059f39SArchie Cobbs if (!isComp) 300069154d5SJulian Elischer priv->ctrlnode = NGI_RETADDR(item); 301af7ab184SArchie Cobbs 302af7ab184SArchie Cobbs /* Configuration is OK, reset to it */ 303af7ab184SArchie Cobbs d->cfg = *cfg; 304af7ab184SArchie Cobbs 305af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION 306af7ab184SArchie Cobbs /* Initialize state buffers for compression */ 307af7ab184SArchie Cobbs if (d->history != NULL) { 3081ede983cSDag-Erling Smørgrav free(d->history, M_NETGRAPH_MPPC); 309af7ab184SArchie Cobbs d->history = NULL; 310af7ab184SArchie Cobbs } 311af7ab184SArchie Cobbs if ((cfg->bits & MPPC_BIT) != 0) { 312e11e3f18SDag-Erling Smørgrav d->history = malloc(isComp ? 313e11e3f18SDag-Erling Smørgrav MPPC_SizeOfCompressionHistory() : 314af7ab184SArchie Cobbs MPPC_SizeOfDecompressionHistory(), 3159c8c302fSJulian Elischer M_NETGRAPH_MPPC, M_NOWAIT); 316af7ab184SArchie Cobbs if (d->history == NULL) 317af7ab184SArchie Cobbs ERROUT(ENOMEM); 318af7ab184SArchie Cobbs if (isComp) 319af7ab184SArchie Cobbs MPPC_InitCompressionHistory(d->history); 320af7ab184SArchie Cobbs else { 321af7ab184SArchie Cobbs MPPC_InitDecompressionHistory( 322af7ab184SArchie Cobbs d->history); 323af7ab184SArchie Cobbs } 324af7ab184SArchie Cobbs } 325af7ab184SArchie Cobbs #endif 326af7ab184SArchie Cobbs 327af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION 328af7ab184SArchie Cobbs /* Generate initial session keys for encryption */ 329af7ab184SArchie Cobbs if ((cfg->bits & MPPE_BITS) != 0) { 330af7ab184SArchie Cobbs const int keylen = KEYLEN(cfg->bits); 331af7ab184SArchie Cobbs 332af7ab184SArchie Cobbs bcopy(cfg->startkey, d->key, keylen); 333af7ab184SArchie Cobbs ng_mppc_getkey(cfg->startkey, d->key, keylen); 33434fd2381SArchie Cobbs if ((cfg->bits & MPPE_40) != 0) 33534fd2381SArchie Cobbs bcopy(&ng_mppe_weakenkey, d->key, 3); 33634fd2381SArchie Cobbs else if ((cfg->bits & MPPE_56) != 0) 33734fd2381SArchie Cobbs bcopy(&ng_mppe_weakenkey, d->key, 1); 338af7ab184SArchie Cobbs rc4_init(&d->rc4, d->key, keylen); 339af7ab184SArchie Cobbs } 340af7ab184SArchie Cobbs #endif 341af7ab184SArchie Cobbs 342af7ab184SArchie Cobbs /* Initialize other state */ 343af7ab184SArchie Cobbs d->cc = 0; 344af7ab184SArchie Cobbs d->flushed = 0; 345af7ab184SArchie Cobbs break; 346af7ab184SArchie Cobbs } 347af7ab184SArchie Cobbs 348af7ab184SArchie Cobbs case NGM_MPPC_RESETREQ: 349af7ab184SArchie Cobbs ng_mppc_reset_req(node); 350af7ab184SArchie Cobbs break; 351af7ab184SArchie Cobbs 352af7ab184SArchie Cobbs default: 353af7ab184SArchie Cobbs error = EINVAL; 354af7ab184SArchie Cobbs break; 355af7ab184SArchie Cobbs } 356af7ab184SArchie Cobbs break; 357af7ab184SArchie Cobbs default: 358af7ab184SArchie Cobbs error = EINVAL; 359af7ab184SArchie Cobbs break; 360af7ab184SArchie Cobbs } 361af7ab184SArchie Cobbs done: 362069154d5SJulian Elischer NG_RESPOND_MSG(error, node, item, resp); 363069154d5SJulian Elischer NG_FREE_MSG(msg); 364af7ab184SArchie Cobbs return (error); 365af7ab184SArchie Cobbs } 366af7ab184SArchie Cobbs 367af7ab184SArchie Cobbs /* 368af7ab184SArchie Cobbs * Receive incoming data on our hook. 369af7ab184SArchie Cobbs */ 370af7ab184SArchie Cobbs static int 371069154d5SJulian Elischer ng_mppc_rcvdata(hook_p hook, item_p item) 372af7ab184SArchie Cobbs { 37330400f03SJulian Elischer const node_p node = NG_HOOK_NODE(hook); 37430400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 375af7ab184SArchie Cobbs int error; 376069154d5SJulian Elischer struct mbuf *m; 377af7ab184SArchie Cobbs 378069154d5SJulian Elischer NGI_GET_M(item, m); 379af7ab184SArchie Cobbs /* Compress and/or encrypt */ 380af7ab184SArchie Cobbs if (hook == priv->xmit.hook) { 381af7ab184SArchie Cobbs if (!priv->xmit.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_compress(node, &m)) != 0) { 387069154d5SJulian Elischer NG_FREE_ITEM(item); 388af7ab184SArchie Cobbs return(error); 389af7ab184SArchie Cobbs } 390ce52e8f4SAlexander Motin NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m); 391af7ab184SArchie Cobbs return (error); 392af7ab184SArchie Cobbs } 393af7ab184SArchie Cobbs 394af7ab184SArchie Cobbs /* Decompress and/or decrypt */ 395af7ab184SArchie Cobbs if (hook == priv->recv.hook) { 396af7ab184SArchie Cobbs if (!priv->recv.cfg.enable) { 397069154d5SJulian Elischer NG_FREE_M(m); 398069154d5SJulian Elischer NG_FREE_ITEM(item); 399af7ab184SArchie Cobbs return (ENXIO); 400af7ab184SArchie Cobbs } 401ce52e8f4SAlexander Motin if ((error = ng_mppc_decompress(node, &m)) != 0) { 402069154d5SJulian Elischer NG_FREE_ITEM(item); 403facfd889SArchie Cobbs if (error == EINVAL && priv->ctrlnode != 0) { 404af7ab184SArchie Cobbs struct ng_mesg *msg; 405af7ab184SArchie Cobbs 406af7ab184SArchie Cobbs /* Need to send a reset-request */ 407af7ab184SArchie Cobbs NG_MKMESSAGE(msg, NGM_MPPC_COOKIE, 408af7ab184SArchie Cobbs NGM_MPPC_RESETREQ, 0, M_NOWAIT); 409af7ab184SArchie Cobbs if (msg == NULL) 410af7ab184SArchie Cobbs return (error); 411069154d5SJulian Elischer NG_SEND_MSG_ID(error, node, msg, 412facfd889SArchie Cobbs priv->ctrlnode, 0); 413af7ab184SArchie Cobbs } 414af7ab184SArchie Cobbs return (error); 415af7ab184SArchie Cobbs } 416ce52e8f4SAlexander Motin NG_FWD_NEW_DATA(error, item, priv->recv.hook, m); 417af7ab184SArchie Cobbs return (error); 418af7ab184SArchie Cobbs } 419af7ab184SArchie Cobbs 420af7ab184SArchie Cobbs /* Oops */ 4216e551fb6SDavid E. O'Brien panic("%s: unknown hook", __func__); 422af7ab184SArchie Cobbs } 423af7ab184SArchie Cobbs 424af7ab184SArchie Cobbs /* 425af7ab184SArchie Cobbs * Destroy node 426af7ab184SArchie Cobbs */ 427af7ab184SArchie Cobbs static int 428069154d5SJulian Elischer ng_mppc_shutdown(node_p node) 429af7ab184SArchie Cobbs { 43030400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 431af7ab184SArchie Cobbs 432af7ab184SArchie Cobbs /* Take down netgraph node */ 433af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION 434af7ab184SArchie Cobbs if (priv->xmit.history != NULL) 4351ede983cSDag-Erling Smørgrav free(priv->xmit.history, M_NETGRAPH_MPPC); 436af7ab184SArchie Cobbs if (priv->recv.history != NULL) 4371ede983cSDag-Erling Smørgrav free(priv->recv.history, M_NETGRAPH_MPPC); 438af7ab184SArchie Cobbs #endif 439af7ab184SArchie Cobbs bzero(priv, sizeof(*priv)); 4401ede983cSDag-Erling Smørgrav free(priv, M_NETGRAPH_MPPC); 44130400f03SJulian Elischer NG_NODE_SET_PRIVATE(node, NULL); 44230400f03SJulian Elischer NG_NODE_UNREF(node); /* let the node escape */ 443af7ab184SArchie Cobbs return (0); 444af7ab184SArchie Cobbs } 445af7ab184SArchie Cobbs 446af7ab184SArchie Cobbs /* 447af7ab184SArchie Cobbs * Hook disconnection 448af7ab184SArchie Cobbs */ 449af7ab184SArchie Cobbs static int 450af7ab184SArchie Cobbs ng_mppc_disconnect(hook_p hook) 451af7ab184SArchie Cobbs { 45230400f03SJulian Elischer const node_p node = NG_HOOK_NODE(hook); 45330400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 454af7ab184SArchie Cobbs 455af7ab184SArchie Cobbs /* Zero out hook pointer */ 456af7ab184SArchie Cobbs if (hook == priv->xmit.hook) 457af7ab184SArchie Cobbs priv->xmit.hook = NULL; 458af7ab184SArchie Cobbs if (hook == priv->recv.hook) 459af7ab184SArchie Cobbs priv->recv.hook = NULL; 460af7ab184SArchie Cobbs 461af7ab184SArchie Cobbs /* Go away if no longer connected */ 46230400f03SJulian Elischer if ((NG_NODE_NUMHOOKS(node) == 0) 46330400f03SJulian Elischer && NG_NODE_IS_VALID(node)) 464069154d5SJulian Elischer ng_rmnode_self(node); 465af7ab184SArchie Cobbs return (0); 466af7ab184SArchie Cobbs } 467af7ab184SArchie Cobbs 468af7ab184SArchie Cobbs /************************************************************************ 469af7ab184SArchie Cobbs HELPER STUFF 470af7ab184SArchie Cobbs ************************************************************************/ 471af7ab184SArchie Cobbs 472af7ab184SArchie Cobbs /* 473af7ab184SArchie Cobbs * Compress/encrypt a packet and put the result in a new mbuf at *resultp. 474af7ab184SArchie Cobbs * The original mbuf is not free'd. 475af7ab184SArchie Cobbs */ 476af7ab184SArchie Cobbs static int 477ce52e8f4SAlexander Motin ng_mppc_compress(node_p node, struct mbuf **datap) 478af7ab184SArchie Cobbs { 47930400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 480af7ab184SArchie Cobbs struct ng_mppc_dir *const d = &priv->xmit; 481af7ab184SArchie Cobbs u_int16_t header; 482ce52e8f4SAlexander Motin struct mbuf *m = *datap; 483af7ab184SArchie Cobbs 484e4651e05SAlexander Motin /* We must own the mbuf chain exclusively to modify it. */ 485eb1b1807SGleb Smirnoff m = m_unshare(m, M_NOWAIT); 486e4651e05SAlexander Motin if (m == NULL) 487e4651e05SAlexander Motin return (ENOMEM); 488e4651e05SAlexander Motin 489af7ab184SArchie Cobbs /* Initialize */ 490af7ab184SArchie Cobbs header = d->cc; 491adecf751SAlexander Motin 492adecf751SAlexander Motin /* Always set the flushed bit in stateless mode */ 493adecf751SAlexander Motin if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) { 494af7ab184SArchie Cobbs header |= MPPC_FLAG_FLUSHED; 495af7ab184SArchie Cobbs d->flushed = 0; 496af7ab184SArchie Cobbs } 497af7ab184SArchie Cobbs 498ce52e8f4SAlexander Motin /* Compress packet (if compression enabled) */ 499af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION 500af7ab184SArchie Cobbs if ((d->cfg.bits & MPPC_BIT) != 0) { 501af7ab184SArchie Cobbs u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS; 502ce52e8f4SAlexander Motin u_char *inbuf, *outbuf; 50367898a23SAlexander Motin int outlen, inlen, ina; 504af7ab184SArchie Cobbs u_char *source, *dest; 505af7ab184SArchie Cobbs u_long sourceCnt, destCnt; 506af7ab184SArchie Cobbs int rtn; 507af7ab184SArchie Cobbs 508ce52e8f4SAlexander Motin /* Work with contiguous regions of memory. */ 509ce52e8f4SAlexander Motin inlen = m->m_pkthdr.len; 51067898a23SAlexander Motin if (m->m_next == NULL) { 51167898a23SAlexander Motin inbuf = mtod(m, u_char *); 51267898a23SAlexander Motin ina = 0; 51367898a23SAlexander Motin } else { 514ce52e8f4SAlexander Motin inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT); 51511d1cadeSAlexander Motin if (inbuf == NULL) 51611d1cadeSAlexander Motin goto err1; 517ce52e8f4SAlexander Motin m_copydata(m, 0, inlen, (caddr_t)inbuf); 51867898a23SAlexander Motin ina = 1; 51967898a23SAlexander Motin } 520ce52e8f4SAlexander Motin 521ce52e8f4SAlexander Motin outlen = MPPC_MAX_BLOWUP(inlen); 522ce52e8f4SAlexander Motin outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT); 523ce52e8f4SAlexander Motin if (outbuf == NULL) { 52467898a23SAlexander Motin if (ina) 525ce52e8f4SAlexander Motin free(inbuf, M_NETGRAPH_MPPC); 52611d1cadeSAlexander Motin err1: 52711d1cadeSAlexander Motin m_freem(m); 52811d1cadeSAlexander Motin MPPC_InitCompressionHistory(d->history); 52911d1cadeSAlexander Motin d->flushed = 1; 530ce52e8f4SAlexander Motin return (ENOMEM); 531ce52e8f4SAlexander Motin } 532ce52e8f4SAlexander Motin 533af7ab184SArchie Cobbs /* Prepare to compress */ 534af7ab184SArchie Cobbs source = inbuf; 535af7ab184SArchie Cobbs sourceCnt = inlen; 536ce52e8f4SAlexander Motin dest = outbuf; 537ce52e8f4SAlexander Motin destCnt = outlen; 538af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_STATELESS) == 0) 539af7ab184SArchie Cobbs flags |= MPPC_SAVE_HISTORY; 540af7ab184SArchie Cobbs 541af7ab184SArchie Cobbs /* Compress */ 542af7ab184SArchie Cobbs rtn = MPPC_Compress(&source, &dest, &sourceCnt, 543af7ab184SArchie Cobbs &destCnt, d->history, flags, 0); 544af7ab184SArchie Cobbs 545af7ab184SArchie Cobbs /* Check return value */ 5466e551fb6SDavid E. O'Brien KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); 547af7ab184SArchie Cobbs if ((rtn & MPPC_EXPANDED) == 0 548af7ab184SArchie Cobbs && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) { 549af7ab184SArchie Cobbs outlen -= destCnt; 550af7ab184SArchie Cobbs header |= MPPC_FLAG_COMPRESSED; 551af7ab184SArchie Cobbs if ((rtn & MPPC_RESTART_HISTORY) != 0) 552af7ab184SArchie Cobbs header |= MPPC_FLAG_RESTART; 553ce52e8f4SAlexander Motin 554ce52e8f4SAlexander Motin /* Replace m by the compresed one. */ 555e4651e05SAlexander Motin m_copyback(m, 0, outlen, (caddr_t)outbuf); 556e4651e05SAlexander Motin if (m->m_pkthdr.len < outlen) { 557ce52e8f4SAlexander Motin m_freem(m); 558e4651e05SAlexander Motin m = NULL; 559e4651e05SAlexander Motin } else if (outlen < m->m_pkthdr.len) 560e4651e05SAlexander Motin m_adj(m, outlen - m->m_pkthdr.len); 561af7ab184SArchie Cobbs } 562af7ab184SArchie Cobbs d->flushed = (rtn & MPPC_EXPANDED) != 0 563af7ab184SArchie Cobbs || (flags & MPPC_SAVE_HISTORY) == 0; 564ce52e8f4SAlexander Motin 56567898a23SAlexander Motin if (ina) 566ce52e8f4SAlexander Motin free(inbuf, M_NETGRAPH_MPPC); 567ce52e8f4SAlexander Motin free(outbuf, M_NETGRAPH_MPPC); 568ce52e8f4SAlexander Motin 569e4651e05SAlexander Motin /* Check mbuf chain reload result. */ 57011d1cadeSAlexander Motin if (m == NULL) { 57111d1cadeSAlexander Motin if (!d->flushed) { 57211d1cadeSAlexander Motin MPPC_InitCompressionHistory(d->history); 57311d1cadeSAlexander Motin d->flushed = 1; 57411d1cadeSAlexander Motin } 575ce52e8f4SAlexander Motin return (ENOMEM); 576af7ab184SArchie Cobbs } 57711d1cadeSAlexander Motin } 578af7ab184SArchie Cobbs #endif 579af7ab184SArchie Cobbs 580af7ab184SArchie Cobbs /* Now encrypt packet (if encryption enabled) */ 581af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION 582af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_BITS) != 0) { 583ce52e8f4SAlexander Motin struct mbuf *m1; 584af7ab184SArchie Cobbs 5856370fd6bSAlexander Motin /* Set header bits */ 586af7ab184SArchie Cobbs header |= MPPC_FLAG_ENCRYPTED; 587af7ab184SArchie Cobbs 588af7ab184SArchie Cobbs /* Update key if it's time */ 589af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_STATELESS) != 0 590af7ab184SArchie Cobbs || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) { 591af7ab184SArchie Cobbs ng_mppc_updatekey(d->cfg.bits, 592af7ab184SArchie Cobbs d->cfg.startkey, d->key, &d->rc4); 5936370fd6bSAlexander Motin } else if ((header & MPPC_FLAG_FLUSHED) != 0) { 5946370fd6bSAlexander Motin /* Need to reset key if we say we did 5956370fd6bSAlexander Motin and ng_mppc_updatekey wasn't called to do it also. */ 5966370fd6bSAlexander Motin rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 597af7ab184SArchie Cobbs } 598af7ab184SArchie Cobbs 599af7ab184SArchie Cobbs /* Encrypt packet */ 600ce52e8f4SAlexander Motin m1 = m; 601ce52e8f4SAlexander Motin while (m1) { 602ce52e8f4SAlexander Motin rc4_crypt(&d->rc4, mtod(m1, u_char *), 603ce52e8f4SAlexander Motin mtod(m1, u_char *), m1->m_len); 604ce52e8f4SAlexander Motin m1 = m1->m_next; 605ce52e8f4SAlexander Motin } 606af7ab184SArchie Cobbs } 607af7ab184SArchie Cobbs #endif 608af7ab184SArchie Cobbs 609755bc287SAlexander Motin /* Update coherency count for next time (12 bit arithmetic) */ 610755bc287SAlexander Motin MPPC_CCOUNT_INC(d->cc); 611af7ab184SArchie Cobbs 612af7ab184SArchie Cobbs /* Install header */ 613eb1b1807SGleb Smirnoff M_PREPEND(m, MPPC_HDRLEN, M_NOWAIT); 614ce52e8f4SAlexander Motin if (m != NULL) 61539228864SAlexander Motin be16enc(mtod(m, void *), header); 616af7ab184SArchie Cobbs 617ce52e8f4SAlexander Motin *datap = m; 618ce52e8f4SAlexander Motin return (*datap == NULL ? ENOBUFS : 0); 619af7ab184SArchie Cobbs } 620af7ab184SArchie Cobbs 621af7ab184SArchie Cobbs /* 622af7ab184SArchie Cobbs * Decompress/decrypt packet and put the result in a new mbuf at *resultp. 623af7ab184SArchie Cobbs * The original mbuf is not free'd. 624af7ab184SArchie Cobbs */ 625af7ab184SArchie Cobbs static int 626ce52e8f4SAlexander Motin ng_mppc_decompress(node_p node, struct mbuf **datap) 627af7ab184SArchie Cobbs { 62830400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 629af7ab184SArchie Cobbs struct ng_mppc_dir *const d = &priv->recv; 630f3059f39SArchie Cobbs u_int16_t header, cc; 631f3059f39SArchie Cobbs u_int numLost; 632ce52e8f4SAlexander Motin struct mbuf *m = *datap; 633af7ab184SArchie Cobbs 634e4651e05SAlexander Motin /* We must own the mbuf chain exclusively to modify it. */ 635eb1b1807SGleb Smirnoff m = m_unshare(m, M_NOWAIT); 636e4651e05SAlexander Motin if (m == NULL) 637e4651e05SAlexander Motin return (ENOMEM); 638e4651e05SAlexander Motin 639af7ab184SArchie Cobbs /* Pull off header */ 640ce52e8f4SAlexander Motin if (m->m_pkthdr.len < MPPC_HDRLEN) { 641ce52e8f4SAlexander Motin m_freem(m); 642af7ab184SArchie Cobbs return (EINVAL); 643ce52e8f4SAlexander Motin } 64439228864SAlexander Motin header = be16dec(mtod(m, void *)); 645af7ab184SArchie Cobbs cc = (header & MPPC_CCOUNT_MASK); 646ce52e8f4SAlexander Motin m_adj(m, MPPC_HDRLEN); 647af7ab184SArchie Cobbs 648f3059f39SArchie Cobbs /* Check for an unexpected jump in the sequence number */ 649af7ab184SArchie Cobbs numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK); 650af7ab184SArchie Cobbs 651af7ab184SArchie Cobbs /* If flushed bit set, we can always handle packet */ 652af7ab184SArchie Cobbs if ((header & MPPC_FLAG_FLUSHED) != 0) { 653af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION 654af7ab184SArchie Cobbs if (d->history != NULL) 655af7ab184SArchie Cobbs MPPC_InitDecompressionHistory(d->history); 656af7ab184SArchie Cobbs #endif 657af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION 658af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_BITS) != 0) { 659f3059f39SArchie Cobbs u_int rekey; 660af7ab184SArchie Cobbs 661f3059f39SArchie Cobbs /* How many times are we going to have to re-key? */ 662f3059f39SArchie Cobbs rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ? 663f3059f39SArchie Cobbs numLost : (numLost / (MPPE_UPDATE_MASK + 1)); 664ee652839SAlexander Motin if (rekey > mppe_max_rekey) { 665ee652839SAlexander Motin if (mppe_block_on_max_rekey) { 666ee652839SAlexander Motin if (mppe_log_max_rekey) { 6675372c30bSGleb Smirnoff log(LOG_ERR, "%s: too many (%d) packets" 668ee652839SAlexander Motin " dropped, disabling node %p!\n", 6695372c30bSGleb Smirnoff __func__, numLost, node); 670ee652839SAlexander Motin } 6715372c30bSGleb Smirnoff priv->recv.cfg.enable = 0; 6725372c30bSGleb Smirnoff goto failed; 673ee652839SAlexander Motin } else { 674ee652839SAlexander Motin if (mppe_log_max_rekey) { 675ee652839SAlexander Motin log(LOG_ERR, "%s: %d packets" 676ee652839SAlexander Motin " dropped, node %p\n", 677ee652839SAlexander Motin __func__, numLost, node); 678ee652839SAlexander Motin } 679ee652839SAlexander Motin goto failed; 680ee652839SAlexander Motin } 6815372c30bSGleb Smirnoff } 682f3059f39SArchie Cobbs 6835372c30bSGleb Smirnoff /* Re-key as necessary to catch up to peer */ 684af7ab184SArchie Cobbs while (d->cc != cc) { 685f3059f39SArchie Cobbs if ((d->cfg.bits & MPPE_STATELESS) != 0 686af7ab184SArchie Cobbs || (d->cc & MPPE_UPDATE_MASK) 687af7ab184SArchie Cobbs == MPPE_UPDATE_FLAG) { 688af7ab184SArchie Cobbs ng_mppc_updatekey(d->cfg.bits, 689af7ab184SArchie Cobbs d->cfg.startkey, d->key, &d->rc4); 690af7ab184SArchie Cobbs } 691755bc287SAlexander Motin MPPC_CCOUNT_INC(d->cc); 692af7ab184SArchie Cobbs } 693af7ab184SArchie Cobbs 694af7ab184SArchie Cobbs /* Reset key (except in stateless mode, see below) */ 695af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_STATELESS) == 0) 696af7ab184SArchie Cobbs rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 697af7ab184SArchie Cobbs } 698af7ab184SArchie Cobbs #endif 699af7ab184SArchie Cobbs d->cc = cc; /* skip over lost seq numbers */ 700af7ab184SArchie Cobbs numLost = 0; /* act like no packets were lost */ 701af7ab184SArchie Cobbs } 702af7ab184SArchie Cobbs 703af7ab184SArchie Cobbs /* Can't decode non-sequential packets without a flushed bit */ 704af7ab184SArchie Cobbs if (numLost != 0) 705af7ab184SArchie Cobbs goto failed; 706af7ab184SArchie Cobbs 707af7ab184SArchie Cobbs /* Decrypt packet */ 708af7ab184SArchie Cobbs if ((header & MPPC_FLAG_ENCRYPTED) != 0) { 709ce52e8f4SAlexander Motin #ifdef NETGRAPH_MPPC_ENCRYPTION 710ce52e8f4SAlexander Motin struct mbuf *m1; 711ce52e8f4SAlexander Motin #endif 712af7ab184SArchie Cobbs 713af7ab184SArchie Cobbs /* Are we not expecting encryption? */ 714af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_BITS) == 0) { 715af7ab184SArchie Cobbs log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 7166e551fb6SDavid E. O'Brien __func__, "encrypted"); 717af7ab184SArchie Cobbs goto failed; 718af7ab184SArchie Cobbs } 719af7ab184SArchie Cobbs 720af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION 721af7ab184SArchie Cobbs /* Update key if it's time (always in stateless mode) */ 722af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_STATELESS) != 0 723af7ab184SArchie Cobbs || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) { 724af7ab184SArchie Cobbs ng_mppc_updatekey(d->cfg.bits, 725af7ab184SArchie Cobbs d->cfg.startkey, d->key, &d->rc4); 726af7ab184SArchie Cobbs } 727af7ab184SArchie Cobbs 728af7ab184SArchie Cobbs /* Decrypt packet */ 729ce52e8f4SAlexander Motin m1 = m; 730ce52e8f4SAlexander Motin while (m1 != NULL) { 731ce52e8f4SAlexander Motin rc4_crypt(&d->rc4, mtod(m1, u_char *), 732ce52e8f4SAlexander Motin mtod(m1, u_char *), m1->m_len); 733ce52e8f4SAlexander Motin m1 = m1->m_next; 734ce52e8f4SAlexander Motin } 735af7ab184SArchie Cobbs #endif 736af7ab184SArchie Cobbs } else { 737af7ab184SArchie Cobbs 738af7ab184SArchie Cobbs /* Are we expecting encryption? */ 739af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_BITS) != 0) { 740af7ab184SArchie Cobbs log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 7416e551fb6SDavid E. O'Brien __func__, "unencrypted"); 742af7ab184SArchie Cobbs goto failed; 743af7ab184SArchie Cobbs } 744af7ab184SArchie Cobbs } 745af7ab184SArchie Cobbs 746af7ab184SArchie Cobbs /* Update coherency count for next time (12 bit arithmetic) */ 747755bc287SAlexander Motin MPPC_CCOUNT_INC(d->cc); 748af7ab184SArchie Cobbs 749af7ab184SArchie Cobbs /* Check for unexpected compressed packet */ 750af7ab184SArchie Cobbs if ((header & MPPC_FLAG_COMPRESSED) != 0 751af7ab184SArchie Cobbs && (d->cfg.bits & MPPC_BIT) == 0) { 752af7ab184SArchie Cobbs log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 7536e551fb6SDavid E. O'Brien __func__, "compressed"); 754af7ab184SArchie Cobbs failed: 755ce52e8f4SAlexander Motin m_freem(m); 756af7ab184SArchie Cobbs return (EINVAL); 757af7ab184SArchie Cobbs } 758af7ab184SArchie Cobbs 759af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION 760af7ab184SArchie Cobbs /* Decompress packet */ 761af7ab184SArchie Cobbs if ((header & MPPC_FLAG_COMPRESSED) != 0) { 762af7ab184SArchie Cobbs int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS; 76367898a23SAlexander Motin u_char *inbuf, *outbuf; 76467898a23SAlexander Motin int inlen, outlen, ina; 76567898a23SAlexander Motin u_char *source, *dest; 766af7ab184SArchie Cobbs u_long sourceCnt, destCnt; 76767898a23SAlexander Motin int rtn; 768ce52e8f4SAlexander Motin 769ce52e8f4SAlexander Motin /* Copy payload into a contiguous region of memory. */ 77067898a23SAlexander Motin inlen = m->m_pkthdr.len; 77167898a23SAlexander Motin if (m->m_next == NULL) { 77267898a23SAlexander Motin inbuf = mtod(m, u_char *); 77367898a23SAlexander Motin ina = 0; 77467898a23SAlexander Motin } else { 77567898a23SAlexander Motin inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT); 77667898a23SAlexander Motin if (inbuf == NULL) { 777ce52e8f4SAlexander Motin m_freem(m); 778ce52e8f4SAlexander Motin return (ENOMEM); 779ce52e8f4SAlexander Motin } 78067898a23SAlexander Motin m_copydata(m, 0, inlen, (caddr_t)inbuf); 78167898a23SAlexander Motin ina = 1; 78267898a23SAlexander Motin } 783af7ab184SArchie Cobbs 784af7ab184SArchie Cobbs /* Allocate a buffer for decompressed data */ 78567898a23SAlexander Motin outbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY, 786ce52e8f4SAlexander Motin M_NETGRAPH_MPPC, M_NOWAIT); 78767898a23SAlexander Motin if (outbuf == NULL) { 788ce52e8f4SAlexander Motin m_freem(m); 78967898a23SAlexander Motin if (ina) 79067898a23SAlexander Motin free(inbuf, M_NETGRAPH_MPPC); 791af7ab184SArchie Cobbs return (ENOMEM); 792af7ab184SArchie Cobbs } 79367898a23SAlexander Motin outlen = MPPC_DECOMP_BUFSIZE; 794af7ab184SArchie Cobbs 795af7ab184SArchie Cobbs /* Prepare to decompress */ 79667898a23SAlexander Motin source = inbuf; 79767898a23SAlexander Motin sourceCnt = inlen; 79867898a23SAlexander Motin dest = outbuf; 79967898a23SAlexander Motin destCnt = outlen; 800af7ab184SArchie Cobbs if ((header & MPPC_FLAG_RESTART) != 0) 801af7ab184SArchie Cobbs flags |= MPPC_RESTART_HISTORY; 802af7ab184SArchie Cobbs 803af7ab184SArchie Cobbs /* Decompress */ 804af7ab184SArchie Cobbs rtn = MPPC_Decompress(&source, &dest, 805af7ab184SArchie Cobbs &sourceCnt, &destCnt, d->history, flags); 806af7ab184SArchie Cobbs 807af7ab184SArchie Cobbs /* Check return value */ 8086e551fb6SDavid E. O'Brien KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); 809af7ab184SArchie Cobbs if ((rtn & MPPC_DEST_EXHAUSTED) != 0 810af7ab184SArchie Cobbs || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) { 811af7ab184SArchie Cobbs log(LOG_ERR, "%s: decomp returned 0x%x", 8126e551fb6SDavid E. O'Brien __func__, rtn); 81367898a23SAlexander Motin if (ina) 81467898a23SAlexander Motin free(inbuf, M_NETGRAPH_MPPC); 81567898a23SAlexander Motin free(outbuf, M_NETGRAPH_MPPC); 816af7ab184SArchie Cobbs goto failed; 817af7ab184SArchie Cobbs } 818af7ab184SArchie Cobbs 819af7ab184SArchie Cobbs /* Replace compressed data with decompressed data */ 82067898a23SAlexander Motin if (ina) 82167898a23SAlexander Motin free(inbuf, M_NETGRAPH_MPPC); 82267898a23SAlexander Motin outlen -= destCnt; 823ce52e8f4SAlexander Motin 82467898a23SAlexander Motin m_copyback(m, 0, outlen, (caddr_t)outbuf); 82567898a23SAlexander Motin if (m->m_pkthdr.len < outlen) { 826ce52e8f4SAlexander Motin m_freem(m); 827e4651e05SAlexander Motin m = NULL; 82867898a23SAlexander Motin } else if (outlen < m->m_pkthdr.len) 82967898a23SAlexander Motin m_adj(m, outlen - m->m_pkthdr.len); 83067898a23SAlexander Motin free(outbuf, M_NETGRAPH_MPPC); 831af7ab184SArchie Cobbs } 832af7ab184SArchie Cobbs #endif 833af7ab184SArchie Cobbs 834af7ab184SArchie Cobbs /* Return result in an mbuf */ 835ce52e8f4SAlexander Motin *datap = m; 836ce52e8f4SAlexander Motin return (*datap == NULL ? ENOBUFS : 0); 837af7ab184SArchie Cobbs } 838af7ab184SArchie Cobbs 839af7ab184SArchie Cobbs /* 840af7ab184SArchie Cobbs * The peer has sent us a CCP ResetRequest, so reset our transmit state. 841af7ab184SArchie Cobbs */ 842af7ab184SArchie Cobbs static void 843af7ab184SArchie Cobbs ng_mppc_reset_req(node_p node) 844af7ab184SArchie Cobbs { 84530400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 846af7ab184SArchie Cobbs struct ng_mppc_dir *const d = &priv->xmit; 847af7ab184SArchie Cobbs 848af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION 849af7ab184SArchie Cobbs if (d->history != NULL) 850af7ab184SArchie Cobbs MPPC_InitCompressionHistory(d->history); 851af7ab184SArchie Cobbs #endif 852af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION 853af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_STATELESS) == 0) 854af7ab184SArchie Cobbs rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 855af7ab184SArchie Cobbs #endif 856af7ab184SArchie Cobbs d->flushed = 1; 857af7ab184SArchie Cobbs } 858af7ab184SArchie Cobbs 85906c51e6eSAlexander Motin #ifdef NETGRAPH_MPPC_ENCRYPTION 860af7ab184SArchie Cobbs /* 861af7ab184SArchie Cobbs * Generate a new encryption key 862af7ab184SArchie Cobbs */ 863af7ab184SArchie Cobbs static void 864af7ab184SArchie Cobbs ng_mppc_getkey(const u_char *h, u_char *h2, int len) 865af7ab184SArchie Cobbs { 866b3d298b9SAlexander Motin static const u_char pad1[40] = 867b3d298b9SAlexander Motin { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 868b3d298b9SAlexander Motin 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 869b3d298b9SAlexander Motin 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 870b3d298b9SAlexander Motin 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 871b3d298b9SAlexander Motin static const u_char pad2[40] = 872b3d298b9SAlexander Motin { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 873b3d298b9SAlexander Motin 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 874b3d298b9SAlexander Motin 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 875b3d298b9SAlexander Motin 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2 }; 876af7ab184SArchie Cobbs u_char hash[20]; 877af7ab184SArchie Cobbs SHA1_CTX c; 878af7ab184SArchie Cobbs 879af7ab184SArchie Cobbs SHA1Init(&c); 880af7ab184SArchie Cobbs SHA1Update(&c, h, len); 881592009a3SAlexander Motin SHA1Update(&c, pad1, sizeof(pad1)); 882af7ab184SArchie Cobbs SHA1Update(&c, h2, len); 883af7ab184SArchie Cobbs SHA1Update(&c, pad2, sizeof(pad2)); 884af7ab184SArchie Cobbs SHA1Final(hash, &c); 885af7ab184SArchie Cobbs bcopy(hash, h2, len); 886af7ab184SArchie Cobbs } 887af7ab184SArchie Cobbs 888af7ab184SArchie Cobbs /* 889af7ab184SArchie Cobbs * Update the encryption key 890af7ab184SArchie Cobbs */ 891af7ab184SArchie Cobbs static void 892af7ab184SArchie Cobbs ng_mppc_updatekey(u_int32_t bits, 893af7ab184SArchie Cobbs u_char *key0, u_char *key, struct rc4_state *rc4) 894af7ab184SArchie Cobbs { 895af7ab184SArchie Cobbs const int keylen = KEYLEN(bits); 896af7ab184SArchie Cobbs 897af7ab184SArchie Cobbs ng_mppc_getkey(key0, key, keylen); 898af7ab184SArchie Cobbs rc4_init(rc4, key, keylen); 899af7ab184SArchie Cobbs rc4_crypt(rc4, key, key, keylen); 90034fd2381SArchie Cobbs if ((bits & MPPE_40) != 0) 90134fd2381SArchie Cobbs bcopy(&ng_mppe_weakenkey, key, 3); 90234fd2381SArchie Cobbs else if ((bits & MPPE_56) != 0) 90334fd2381SArchie Cobbs bcopy(&ng_mppe_weakenkey, key, 1); 904af7ab184SArchie Cobbs rc4_init(rc4, key, keylen); 905af7ab184SArchie Cobbs } 90606c51e6eSAlexander Motin #endif 907af7ab184SArchie Cobbs 908