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