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 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_NOWAIT | M_ZERO); 205 if (priv == NULL) 206 return (ENOMEM); 207 208 NG_NODE_SET_PRIVATE(node, priv); 209 210 /* This node is not thread safe. */ 211 NG_NODE_FORCE_WRITER(node); 212 213 /* Done */ 214 return (0); 215 } 216 217 /* 218 * Give our OK for a hook to be added 219 */ 220 static int 221 ng_mppc_newhook(node_p node, hook_p hook, const char *name) 222 { 223 const priv_p priv = NG_NODE_PRIVATE(node); 224 hook_p *hookPtr; 225 226 /* Check hook name */ 227 if (strcmp(name, NG_MPPC_HOOK_COMP) == 0) 228 hookPtr = &priv->xmit.hook; 229 else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0) 230 hookPtr = &priv->recv.hook; 231 else 232 return (EINVAL); 233 234 /* See if already connected */ 235 if (*hookPtr != NULL) 236 return (EISCONN); 237 238 /* OK */ 239 *hookPtr = hook; 240 return (0); 241 } 242 243 /* 244 * Receive a control message 245 */ 246 static int 247 ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook) 248 { 249 const priv_p priv = NG_NODE_PRIVATE(node); 250 struct ng_mesg *resp = NULL; 251 int error = 0; 252 struct ng_mesg *msg; 253 254 NGI_GET_MSG(item, msg); 255 switch (msg->header.typecookie) { 256 case NGM_MPPC_COOKIE: 257 switch (msg->header.cmd) { 258 case NGM_MPPC_CONFIG_COMP: 259 case NGM_MPPC_CONFIG_DECOMP: 260 { 261 struct ng_mppc_config *const cfg 262 = (struct ng_mppc_config *)msg->data; 263 const int isComp = 264 msg->header.cmd == NGM_MPPC_CONFIG_COMP; 265 struct ng_mppc_dir *const d = isComp ? 266 &priv->xmit : &priv->recv; 267 268 /* Check configuration */ 269 if (msg->header.arglen != sizeof(*cfg)) 270 ERROUT(EINVAL); 271 if (cfg->enable) { 272 if ((cfg->bits & ~MPPC_VALID_BITS) != 0) 273 ERROUT(EINVAL); 274 #ifndef NETGRAPH_MPPC_COMPRESSION 275 if ((cfg->bits & MPPC_BIT) != 0) 276 ERROUT(EPROTONOSUPPORT); 277 #endif 278 #ifndef NETGRAPH_MPPC_ENCRYPTION 279 if ((cfg->bits & MPPE_BITS) != 0) 280 ERROUT(EPROTONOSUPPORT); 281 #endif 282 } else 283 cfg->bits = 0; 284 285 /* Save return address so we can send reset-req's */ 286 if (!isComp) 287 priv->ctrlnode = NGI_RETADDR(item); 288 289 /* Configuration is OK, reset to it */ 290 d->cfg = *cfg; 291 292 #ifdef NETGRAPH_MPPC_COMPRESSION 293 /* Initialize state buffers for compression */ 294 if (d->history != NULL) { 295 free(d->history, M_NETGRAPH_MPPC); 296 d->history = NULL; 297 } 298 if ((cfg->bits & MPPC_BIT) != 0) { 299 d->history = malloc(isComp ? 300 MPPC_SizeOfCompressionHistory() : 301 MPPC_SizeOfDecompressionHistory(), 302 M_NETGRAPH_MPPC, M_NOWAIT); 303 if (d->history == NULL) 304 ERROUT(ENOMEM); 305 if (isComp) 306 MPPC_InitCompressionHistory(d->history); 307 else { 308 MPPC_InitDecompressionHistory( 309 d->history); 310 } 311 } 312 #endif 313 314 #ifdef NETGRAPH_MPPC_ENCRYPTION 315 /* Generate initial session keys for encryption */ 316 if ((cfg->bits & MPPE_BITS) != 0) { 317 const int keylen = KEYLEN(cfg->bits); 318 319 bcopy(cfg->startkey, d->key, keylen); 320 ng_mppc_getkey(cfg->startkey, d->key, keylen); 321 if ((cfg->bits & MPPE_40) != 0) 322 bcopy(&ng_mppe_weakenkey, d->key, 3); 323 else if ((cfg->bits & MPPE_56) != 0) 324 bcopy(&ng_mppe_weakenkey, d->key, 1); 325 rc4_init(&d->rc4, d->key, keylen); 326 } 327 #endif 328 329 /* Initialize other state */ 330 d->cc = 0; 331 d->flushed = 0; 332 break; 333 } 334 335 case NGM_MPPC_RESETREQ: 336 ng_mppc_reset_req(node); 337 break; 338 339 default: 340 error = EINVAL; 341 break; 342 } 343 break; 344 default: 345 error = EINVAL; 346 break; 347 } 348 done: 349 NG_RESPOND_MSG(error, node, item, resp); 350 NG_FREE_MSG(msg); 351 return (error); 352 } 353 354 /* 355 * Receive incoming data on our hook. 356 */ 357 static int 358 ng_mppc_rcvdata(hook_p hook, item_p item) 359 { 360 const node_p node = NG_HOOK_NODE(hook); 361 const priv_p priv = NG_NODE_PRIVATE(node); 362 int error; 363 struct mbuf *m; 364 365 NGI_GET_M(item, m); 366 /* Compress and/or encrypt */ 367 if (hook == priv->xmit.hook) { 368 if (!priv->xmit.cfg.enable) { 369 NG_FREE_M(m); 370 NG_FREE_ITEM(item); 371 return (ENXIO); 372 } 373 if ((error = ng_mppc_compress(node, &m)) != 0) { 374 NG_FREE_ITEM(item); 375 return(error); 376 } 377 NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m); 378 return (error); 379 } 380 381 /* Decompress and/or decrypt */ 382 if (hook == priv->recv.hook) { 383 if (!priv->recv.cfg.enable) { 384 NG_FREE_M(m); 385 NG_FREE_ITEM(item); 386 return (ENXIO); 387 } 388 if ((error = ng_mppc_decompress(node, &m)) != 0) { 389 NG_FREE_ITEM(item); 390 if (error == EINVAL && priv->ctrlnode != 0) { 391 struct ng_mesg *msg; 392 393 /* Need to send a reset-request */ 394 NG_MKMESSAGE(msg, NGM_MPPC_COOKIE, 395 NGM_MPPC_RESETREQ, 0, M_NOWAIT); 396 if (msg == NULL) 397 return (error); 398 NG_SEND_MSG_ID(error, node, msg, 399 priv->ctrlnode, 0); 400 } 401 return (error); 402 } 403 NG_FWD_NEW_DATA(error, item, priv->recv.hook, m); 404 return (error); 405 } 406 407 /* Oops */ 408 panic("%s: unknown hook", __func__); 409 #ifdef RESTARTABLE_PANICS 410 return (EINVAL); 411 #endif 412 } 413 414 /* 415 * Destroy node 416 */ 417 static int 418 ng_mppc_shutdown(node_p node) 419 { 420 const priv_p priv = NG_NODE_PRIVATE(node); 421 422 /* Take down netgraph node */ 423 #ifdef NETGRAPH_MPPC_COMPRESSION 424 if (priv->xmit.history != NULL) 425 free(priv->xmit.history, M_NETGRAPH_MPPC); 426 if (priv->recv.history != NULL) 427 free(priv->recv.history, M_NETGRAPH_MPPC); 428 #endif 429 bzero(priv, sizeof(*priv)); 430 free(priv, M_NETGRAPH_MPPC); 431 NG_NODE_SET_PRIVATE(node, NULL); 432 NG_NODE_UNREF(node); /* let the node escape */ 433 return (0); 434 } 435 436 /* 437 * Hook disconnection 438 */ 439 static int 440 ng_mppc_disconnect(hook_p hook) 441 { 442 const node_p node = NG_HOOK_NODE(hook); 443 const priv_p priv = NG_NODE_PRIVATE(node); 444 445 /* Zero out hook pointer */ 446 if (hook == priv->xmit.hook) 447 priv->xmit.hook = NULL; 448 if (hook == priv->recv.hook) 449 priv->recv.hook = NULL; 450 451 /* Go away if no longer connected */ 452 if ((NG_NODE_NUMHOOKS(node) == 0) 453 && NG_NODE_IS_VALID(node)) 454 ng_rmnode_self(node); 455 return (0); 456 } 457 458 /************************************************************************ 459 HELPER STUFF 460 ************************************************************************/ 461 462 /* 463 * Compress/encrypt a packet and put the result in a new mbuf at *resultp. 464 * The original mbuf is not free'd. 465 */ 466 static int 467 ng_mppc_compress(node_p node, struct mbuf **datap) 468 { 469 const priv_p priv = NG_NODE_PRIVATE(node); 470 struct ng_mppc_dir *const d = &priv->xmit; 471 u_int16_t header; 472 struct mbuf *m = *datap; 473 474 /* We must own the mbuf chain exclusively to modify it. */ 475 m = m_unshare(m, M_DONTWAIT); 476 if (m == NULL) 477 return (ENOMEM); 478 479 /* Initialize */ 480 header = d->cc; 481 482 /* Always set the flushed bit in stateless mode */ 483 if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) { 484 header |= MPPC_FLAG_FLUSHED; 485 d->flushed = 0; 486 } 487 488 /* Compress packet (if compression enabled) */ 489 #ifdef NETGRAPH_MPPC_COMPRESSION 490 if ((d->cfg.bits & MPPC_BIT) != 0) { 491 u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS; 492 u_char *inbuf, *outbuf; 493 int outlen, inlen, ina; 494 u_char *source, *dest; 495 u_long sourceCnt, destCnt; 496 int rtn; 497 498 /* Work with contiguous regions of memory. */ 499 inlen = m->m_pkthdr.len; 500 if (m->m_next == NULL) { 501 inbuf = mtod(m, u_char *); 502 ina = 0; 503 } else { 504 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT); 505 if (inbuf == NULL) 506 goto err1; 507 m_copydata(m, 0, inlen, (caddr_t)inbuf); 508 ina = 1; 509 } 510 511 outlen = MPPC_MAX_BLOWUP(inlen); 512 outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT); 513 if (outbuf == NULL) { 514 if (ina) 515 free(inbuf, M_NETGRAPH_MPPC); 516 err1: 517 m_freem(m); 518 MPPC_InitCompressionHistory(d->history); 519 d->flushed = 1; 520 return (ENOMEM); 521 } 522 523 /* Prepare to compress */ 524 source = inbuf; 525 sourceCnt = inlen; 526 dest = outbuf; 527 destCnt = outlen; 528 if ((d->cfg.bits & MPPE_STATELESS) == 0) 529 flags |= MPPC_SAVE_HISTORY; 530 531 /* Compress */ 532 rtn = MPPC_Compress(&source, &dest, &sourceCnt, 533 &destCnt, d->history, flags, 0); 534 535 /* Check return value */ 536 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); 537 if ((rtn & MPPC_EXPANDED) == 0 538 && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) { 539 outlen -= destCnt; 540 header |= MPPC_FLAG_COMPRESSED; 541 if ((rtn & MPPC_RESTART_HISTORY) != 0) 542 header |= MPPC_FLAG_RESTART; 543 544 /* Replace m by the compresed one. */ 545 m_copyback(m, 0, outlen, (caddr_t)outbuf); 546 if (m->m_pkthdr.len < outlen) { 547 m_freem(m); 548 m = NULL; 549 } else if (outlen < m->m_pkthdr.len) 550 m_adj(m, outlen - m->m_pkthdr.len); 551 } 552 d->flushed = (rtn & MPPC_EXPANDED) != 0 553 || (flags & MPPC_SAVE_HISTORY) == 0; 554 555 if (ina) 556 free(inbuf, M_NETGRAPH_MPPC); 557 free(outbuf, M_NETGRAPH_MPPC); 558 559 /* Check mbuf chain reload result. */ 560 if (m == NULL) { 561 if (!d->flushed) { 562 MPPC_InitCompressionHistory(d->history); 563 d->flushed = 1; 564 } 565 return (ENOMEM); 566 } 567 } 568 #endif 569 570 /* Now encrypt packet (if encryption enabled) */ 571 #ifdef NETGRAPH_MPPC_ENCRYPTION 572 if ((d->cfg.bits & MPPE_BITS) != 0) { 573 struct mbuf *m1; 574 575 /* Set header bits */ 576 header |= MPPC_FLAG_ENCRYPTED; 577 578 /* Update key if it's time */ 579 if ((d->cfg.bits & MPPE_STATELESS) != 0 580 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) { 581 ng_mppc_updatekey(d->cfg.bits, 582 d->cfg.startkey, d->key, &d->rc4); 583 } else if ((header & MPPC_FLAG_FLUSHED) != 0) { 584 /* Need to reset key if we say we did 585 and ng_mppc_updatekey wasn't called to do it also. */ 586 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 587 } 588 589 /* Encrypt packet */ 590 m1 = m; 591 while (m1) { 592 rc4_crypt(&d->rc4, mtod(m1, u_char *), 593 mtod(m1, u_char *), m1->m_len); 594 m1 = m1->m_next; 595 } 596 } 597 #endif 598 599 /* Update coherency count for next time (12 bit arithmetic) */ 600 MPPC_CCOUNT_INC(d->cc); 601 602 /* Install header */ 603 M_PREPEND(m, MPPC_HDRLEN, M_DONTWAIT); 604 if (m != NULL) 605 be16enc(mtod(m, void *), header); 606 607 *datap = m; 608 return (*datap == NULL ? ENOBUFS : 0); 609 } 610 611 /* 612 * Decompress/decrypt packet and put the result in a new mbuf at *resultp. 613 * The original mbuf is not free'd. 614 */ 615 static int 616 ng_mppc_decompress(node_p node, struct mbuf **datap) 617 { 618 const priv_p priv = NG_NODE_PRIVATE(node); 619 struct ng_mppc_dir *const d = &priv->recv; 620 u_int16_t header, cc; 621 u_int numLost; 622 struct mbuf *m = *datap; 623 624 /* We must own the mbuf chain exclusively to modify it. */ 625 m = m_unshare(m, M_DONTWAIT); 626 if (m == NULL) 627 return (ENOMEM); 628 629 /* Pull off header */ 630 if (m->m_pkthdr.len < MPPC_HDRLEN) { 631 m_freem(m); 632 return (EINVAL); 633 } 634 header = be16dec(mtod(m, void *)); 635 cc = (header & MPPC_CCOUNT_MASK); 636 m_adj(m, MPPC_HDRLEN); 637 638 /* Check for an unexpected jump in the sequence number */ 639 numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK); 640 641 /* If flushed bit set, we can always handle packet */ 642 if ((header & MPPC_FLAG_FLUSHED) != 0) { 643 #ifdef NETGRAPH_MPPC_COMPRESSION 644 if (d->history != NULL) 645 MPPC_InitDecompressionHistory(d->history); 646 #endif 647 #ifdef NETGRAPH_MPPC_ENCRYPTION 648 if ((d->cfg.bits & MPPE_BITS) != 0) { 649 u_int rekey; 650 651 /* How many times are we going to have to re-key? */ 652 rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ? 653 numLost : (numLost / (MPPE_UPDATE_MASK + 1)); 654 if (rekey > MPPE_MAX_REKEY) { 655 log(LOG_ERR, "%s: too many (%d) packets" 656 " dropped, disabling node %p!", 657 __func__, numLost, node); 658 priv->recv.cfg.enable = 0; 659 goto failed; 660 } 661 662 /* Re-key as necessary to catch up to peer */ 663 while (d->cc != cc) { 664 if ((d->cfg.bits & MPPE_STATELESS) != 0 665 || (d->cc & MPPE_UPDATE_MASK) 666 == MPPE_UPDATE_FLAG) { 667 ng_mppc_updatekey(d->cfg.bits, 668 d->cfg.startkey, d->key, &d->rc4); 669 } 670 MPPC_CCOUNT_INC(d->cc); 671 } 672 673 /* Reset key (except in stateless mode, see below) */ 674 if ((d->cfg.bits & MPPE_STATELESS) == 0) 675 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 676 } 677 #endif 678 d->cc = cc; /* skip over lost seq numbers */ 679 numLost = 0; /* act like no packets were lost */ 680 } 681 682 /* Can't decode non-sequential packets without a flushed bit */ 683 if (numLost != 0) 684 goto failed; 685 686 /* Decrypt packet */ 687 if ((header & MPPC_FLAG_ENCRYPTED) != 0) { 688 #ifdef NETGRAPH_MPPC_ENCRYPTION 689 struct mbuf *m1; 690 #endif 691 692 /* Are we not expecting encryption? */ 693 if ((d->cfg.bits & MPPE_BITS) == 0) { 694 log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 695 __func__, "encrypted"); 696 goto failed; 697 } 698 699 #ifdef NETGRAPH_MPPC_ENCRYPTION 700 /* Update key if it's time (always in stateless mode) */ 701 if ((d->cfg.bits & MPPE_STATELESS) != 0 702 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) { 703 ng_mppc_updatekey(d->cfg.bits, 704 d->cfg.startkey, d->key, &d->rc4); 705 } 706 707 /* Decrypt packet */ 708 m1 = m; 709 while (m1 != NULL) { 710 rc4_crypt(&d->rc4, mtod(m1, u_char *), 711 mtod(m1, u_char *), m1->m_len); 712 m1 = m1->m_next; 713 } 714 #endif 715 } else { 716 717 /* Are we expecting encryption? */ 718 if ((d->cfg.bits & MPPE_BITS) != 0) { 719 log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 720 __func__, "unencrypted"); 721 goto failed; 722 } 723 } 724 725 /* Update coherency count for next time (12 bit arithmetic) */ 726 MPPC_CCOUNT_INC(d->cc); 727 728 /* Check for unexpected compressed packet */ 729 if ((header & MPPC_FLAG_COMPRESSED) != 0 730 && (d->cfg.bits & MPPC_BIT) == 0) { 731 log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 732 __func__, "compressed"); 733 failed: 734 m_freem(m); 735 return (EINVAL); 736 } 737 738 #ifdef NETGRAPH_MPPC_COMPRESSION 739 /* Decompress packet */ 740 if ((header & MPPC_FLAG_COMPRESSED) != 0) { 741 int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS; 742 u_char *inbuf, *outbuf; 743 int inlen, outlen, ina; 744 u_char *source, *dest; 745 u_long sourceCnt, destCnt; 746 int rtn; 747 748 /* Copy payload into a contiguous region of memory. */ 749 inlen = m->m_pkthdr.len; 750 if (m->m_next == NULL) { 751 inbuf = mtod(m, u_char *); 752 ina = 0; 753 } else { 754 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT); 755 if (inbuf == NULL) { 756 m_freem(m); 757 return (ENOMEM); 758 } 759 m_copydata(m, 0, inlen, (caddr_t)inbuf); 760 ina = 1; 761 } 762 763 /* Allocate a buffer for decompressed data */ 764 outbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY, 765 M_NETGRAPH_MPPC, M_NOWAIT); 766 if (outbuf == NULL) { 767 m_freem(m); 768 if (ina) 769 free(inbuf, M_NETGRAPH_MPPC); 770 return (ENOMEM); 771 } 772 outlen = MPPC_DECOMP_BUFSIZE; 773 774 /* Prepare to decompress */ 775 source = inbuf; 776 sourceCnt = inlen; 777 dest = outbuf; 778 destCnt = outlen; 779 if ((header & MPPC_FLAG_RESTART) != 0) 780 flags |= MPPC_RESTART_HISTORY; 781 782 /* Decompress */ 783 rtn = MPPC_Decompress(&source, &dest, 784 &sourceCnt, &destCnt, d->history, flags); 785 786 /* Check return value */ 787 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); 788 if ((rtn & MPPC_DEST_EXHAUSTED) != 0 789 || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) { 790 log(LOG_ERR, "%s: decomp returned 0x%x", 791 __func__, rtn); 792 if (ina) 793 free(inbuf, M_NETGRAPH_MPPC); 794 free(outbuf, M_NETGRAPH_MPPC); 795 goto failed; 796 } 797 798 /* Replace compressed data with decompressed data */ 799 if (ina) 800 free(inbuf, M_NETGRAPH_MPPC); 801 outlen -= destCnt; 802 803 m_copyback(m, 0, outlen, (caddr_t)outbuf); 804 if (m->m_pkthdr.len < outlen) { 805 m_freem(m); 806 m = NULL; 807 } else if (outlen < m->m_pkthdr.len) 808 m_adj(m, outlen - m->m_pkthdr.len); 809 free(outbuf, M_NETGRAPH_MPPC); 810 } 811 #endif 812 813 /* Return result in an mbuf */ 814 *datap = m; 815 return (*datap == NULL ? ENOBUFS : 0); 816 } 817 818 /* 819 * The peer has sent us a CCP ResetRequest, so reset our transmit state. 820 */ 821 static void 822 ng_mppc_reset_req(node_p node) 823 { 824 const priv_p priv = NG_NODE_PRIVATE(node); 825 struct ng_mppc_dir *const d = &priv->xmit; 826 827 #ifdef NETGRAPH_MPPC_COMPRESSION 828 if (d->history != NULL) 829 MPPC_InitCompressionHistory(d->history); 830 #endif 831 #ifdef NETGRAPH_MPPC_ENCRYPTION 832 if ((d->cfg.bits & MPPE_STATELESS) == 0) 833 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 834 #endif 835 d->flushed = 1; 836 } 837 838 #ifdef NETGRAPH_MPPC_ENCRYPTION 839 /* 840 * Generate a new encryption key 841 */ 842 static void 843 ng_mppc_getkey(const u_char *h, u_char *h2, int len) 844 { 845 static const u_char pad1[40] = 846 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 847 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 848 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 849 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 850 static const u_char pad2[40] = 851 { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 852 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 853 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 854 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2 }; 855 u_char hash[20]; 856 SHA1_CTX c; 857 858 SHA1Init(&c); 859 SHA1Update(&c, h, len); 860 SHA1Update(&c, pad1, sizeof(pad1)); 861 SHA1Update(&c, h2, len); 862 SHA1Update(&c, pad2, sizeof(pad2)); 863 SHA1Final(hash, &c); 864 bcopy(hash, h2, len); 865 } 866 867 /* 868 * Update the encryption key 869 */ 870 static void 871 ng_mppc_updatekey(u_int32_t bits, 872 u_char *key0, u_char *key, struct rc4_state *rc4) 873 { 874 const int keylen = KEYLEN(bits); 875 876 ng_mppc_getkey(key0, key, keylen); 877 rc4_init(rc4, key, keylen); 878 rc4_crypt(rc4, key, key, keylen); 879 if ((bits & MPPE_40) != 0) 880 bcopy(&ng_mppe_weakenkey, key, 3); 881 else if ((bits & MPPE_56) != 0) 882 bcopy(&ng_mppe_weakenkey, key, 1); 883 rc4_init(rc4, key, keylen); 884 } 885 #endif 886 887