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