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