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/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 76 MALLOC_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 */ 125 struct 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 */ 140 struct 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 }; 145 typedef struct ng_mppc_private *priv_p; 146 147 /* Netgraph node methods */ 148 static ng_constructor_t ng_mppc_constructor; 149 static ng_rcvmsg_t ng_mppc_rcvmsg; 150 static ng_shutdown_t ng_mppc_shutdown; 151 static ng_newhook_t ng_mppc_newhook; 152 static ng_rcvdata_t ng_mppc_rcvdata; 153 static ng_disconnect_t ng_mppc_disconnect; 154 155 /* Helper functions */ 156 static int ng_mppc_compress(node_p node, 157 struct mbuf **datap); 158 static int ng_mppc_decompress(node_p node, 159 struct mbuf **datap); 160 #ifdef NETGRAPH_MPPC_ENCRYPTION 161 static void ng_mppc_getkey(const u_char *h, u_char *h2, int len); 162 static void ng_mppc_updatekey(u_int32_t bits, 163 u_char *key0, u_char *key, struct rc4_state *rc4); 164 #endif 165 static void ng_mppc_reset_req(node_p node); 166 167 /* Node type descriptor */ 168 static 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 }; 178 NETGRAPH_INIT(mppc, &ng_mppc_typestruct); 179 180 #ifdef NETGRAPH_MPPC_ENCRYPTION 181 /* Depend on separate rc4 module */ 182 MODULE_DEPEND(ng_mppc, rc4, 1, 1, 1); 183 #endif 184 185 /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */ 186 static 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 */ 197 static int 198 ng_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 */ 219 static int 220 ng_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 */ 245 static int 246 ng_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 } 347 done: 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 */ 356 static int 357 ng_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 */ 416 static int 417 ng_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 */ 438 static int 439 ng_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 */ 465 static int 466 ng_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 /* Initialize */ 474 header = d->cc; 475 476 /* Always set the flushed bit in stateless mode */ 477 if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) { 478 header |= MPPC_FLAG_FLUSHED; 479 d->flushed = 0; 480 } 481 482 /* Compress packet (if compression enabled) */ 483 #ifdef NETGRAPH_MPPC_COMPRESSION 484 if ((d->cfg.bits & MPPC_BIT) != 0) { 485 u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS; 486 u_char *inbuf, *outbuf; 487 int outlen, inlen; 488 u_char *source, *dest; 489 u_long sourceCnt, destCnt; 490 int rtn; 491 492 /* Work with contiguous regions of memory. */ 493 inlen = m->m_pkthdr.len; 494 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT); 495 if (inbuf == NULL) 496 goto err1; 497 m_copydata(m, 0, inlen, (caddr_t)inbuf); 498 499 outlen = MPPC_MAX_BLOWUP(inlen); 500 outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT); 501 if (outbuf == NULL) { 502 free(inbuf, M_NETGRAPH_MPPC); 503 err1: 504 m_freem(m); 505 MPPC_InitCompressionHistory(d->history); 506 d->flushed = 1; 507 return (ENOMEM); 508 } 509 510 /* Prepare to compress */ 511 source = inbuf; 512 sourceCnt = inlen; 513 dest = outbuf; 514 destCnt = outlen; 515 if ((d->cfg.bits & MPPE_STATELESS) == 0) 516 flags |= MPPC_SAVE_HISTORY; 517 518 /* Compress */ 519 rtn = MPPC_Compress(&source, &dest, &sourceCnt, 520 &destCnt, d->history, flags, 0); 521 522 /* Check return value */ 523 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); 524 if ((rtn & MPPC_EXPANDED) == 0 525 && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) { 526 outlen -= destCnt; 527 header |= MPPC_FLAG_COMPRESSED; 528 if ((rtn & MPPC_RESTART_HISTORY) != 0) 529 header |= MPPC_FLAG_RESTART; 530 531 /* Replace m by the compresed one. */ 532 m_freem(m); 533 m = m_devget((caddr_t)outbuf, outlen, 0, NULL, NULL); 534 } 535 d->flushed = (rtn & MPPC_EXPANDED) != 0 536 || (flags & MPPC_SAVE_HISTORY) == 0; 537 538 free(inbuf, M_NETGRAPH_MPPC); 539 free(outbuf, M_NETGRAPH_MPPC); 540 541 /* Check m_devget() result. */ 542 if (m == NULL) { 543 if (!d->flushed) { 544 MPPC_InitCompressionHistory(d->history); 545 d->flushed = 1; 546 } 547 return (ENOMEM); 548 } 549 } 550 #endif 551 552 /* Now encrypt packet (if encryption enabled) */ 553 #ifdef NETGRAPH_MPPC_ENCRYPTION 554 if ((d->cfg.bits & MPPE_BITS) != 0) { 555 struct mbuf *m1; 556 557 /* Set header bits */ 558 header |= MPPC_FLAG_ENCRYPTED; 559 560 /* We must own the mbuf chain exclusively to modify it. */ 561 m = m_unshare(m, M_DONTWAIT); 562 if (m == NULL) { 563 if (!d->flushed) { 564 #ifdef NETGRAPH_MPPC_COMPRESSION 565 MPPC_InitCompressionHistory(d->history); 566 #endif 567 d->flushed = 1; 568 } 569 return (ENOMEM); 570 } 571 572 /* Update key if it's time */ 573 if ((d->cfg.bits & MPPE_STATELESS) != 0 574 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) { 575 ng_mppc_updatekey(d->cfg.bits, 576 d->cfg.startkey, d->key, &d->rc4); 577 } else if ((header & MPPC_FLAG_FLUSHED) != 0) { 578 /* Need to reset key if we say we did 579 and ng_mppc_updatekey wasn't called to do it also. */ 580 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 581 } 582 583 /* Encrypt packet */ 584 m1 = m; 585 while (m1) { 586 rc4_crypt(&d->rc4, mtod(m1, u_char *), 587 mtod(m1, u_char *), m1->m_len); 588 m1 = m1->m_next; 589 } 590 } 591 #endif 592 593 /* Update coherency count for next time (12 bit arithmetic) */ 594 MPPC_CCOUNT_INC(d->cc); 595 596 /* Install header */ 597 M_PREPEND(m, MPPC_HDRLEN, M_DONTWAIT); 598 if (m != NULL) 599 *(mtod(m, uint16_t *)) = htons(header); 600 601 *datap = m; 602 return (*datap == NULL ? ENOBUFS : 0); 603 } 604 605 /* 606 * Decompress/decrypt packet and put the result in a new mbuf at *resultp. 607 * The original mbuf is not free'd. 608 */ 609 static int 610 ng_mppc_decompress(node_p node, struct mbuf **datap) 611 { 612 const priv_p priv = NG_NODE_PRIVATE(node); 613 struct ng_mppc_dir *const d = &priv->recv; 614 u_int16_t header, cc; 615 u_int numLost; 616 struct mbuf *m = *datap; 617 618 /* Pull off header */ 619 if (m->m_pkthdr.len < MPPC_HDRLEN) { 620 m_freem(m); 621 return (EINVAL); 622 } 623 m_copydata(m, 0, MPPC_HDRLEN, (caddr_t)&header); 624 header = ntohs(header); 625 cc = (header & MPPC_CCOUNT_MASK); 626 m_adj(m, MPPC_HDRLEN); 627 628 /* Check for an unexpected jump in the sequence number */ 629 numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK); 630 631 /* If flushed bit set, we can always handle packet */ 632 if ((header & MPPC_FLAG_FLUSHED) != 0) { 633 #ifdef NETGRAPH_MPPC_COMPRESSION 634 if (d->history != NULL) 635 MPPC_InitDecompressionHistory(d->history); 636 #endif 637 #ifdef NETGRAPH_MPPC_ENCRYPTION 638 if ((d->cfg.bits & MPPE_BITS) != 0) { 639 u_int rekey; 640 641 /* How many times are we going to have to re-key? */ 642 rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ? 643 numLost : (numLost / (MPPE_UPDATE_MASK + 1)); 644 if (rekey > MPPE_MAX_REKEY) { 645 log(LOG_ERR, "%s: too many (%d) packets" 646 " dropped, disabling node %p!", 647 __func__, numLost, node); 648 priv->recv.cfg.enable = 0; 649 goto failed; 650 } 651 652 /* Re-key as necessary to catch up to peer */ 653 while (d->cc != cc) { 654 if ((d->cfg.bits & MPPE_STATELESS) != 0 655 || (d->cc & MPPE_UPDATE_MASK) 656 == MPPE_UPDATE_FLAG) { 657 ng_mppc_updatekey(d->cfg.bits, 658 d->cfg.startkey, d->key, &d->rc4); 659 } 660 MPPC_CCOUNT_INC(d->cc); 661 } 662 663 /* Reset key (except in stateless mode, see below) */ 664 if ((d->cfg.bits & MPPE_STATELESS) == 0) 665 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 666 } 667 #endif 668 d->cc = cc; /* skip over lost seq numbers */ 669 numLost = 0; /* act like no packets were lost */ 670 } 671 672 /* Can't decode non-sequential packets without a flushed bit */ 673 if (numLost != 0) 674 goto failed; 675 676 /* Decrypt packet */ 677 if ((header & MPPC_FLAG_ENCRYPTED) != 0) { 678 #ifdef NETGRAPH_MPPC_ENCRYPTION 679 struct mbuf *m1; 680 #endif 681 682 /* Are we not expecting encryption? */ 683 if ((d->cfg.bits & MPPE_BITS) == 0) { 684 log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 685 __func__, "encrypted"); 686 goto failed; 687 } 688 689 #ifdef NETGRAPH_MPPC_ENCRYPTION 690 /* Update key if it's time (always in stateless mode) */ 691 if ((d->cfg.bits & MPPE_STATELESS) != 0 692 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) { 693 ng_mppc_updatekey(d->cfg.bits, 694 d->cfg.startkey, d->key, &d->rc4); 695 } 696 697 /* We must own the mbuf chain exclusively to modify it. */ 698 m = m_unshare(m, M_DONTWAIT); 699 if (m == NULL) 700 return (ENOMEM); 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 *decompbuf, *source, *dest; 738 u_long sourceCnt, destCnt; 739 int decomplen, rtn; 740 u_char *buf; 741 int len; 742 743 /* Copy payload into a contiguous region of memory. */ 744 len = m->m_pkthdr.len; 745 buf = malloc(len, M_NETGRAPH_MPPC, M_NOWAIT); 746 if (buf == NULL) { 747 m_freem(m); 748 return (ENOMEM); 749 } 750 m_copydata(m, 0, len, (caddr_t)buf); 751 752 /* Allocate a buffer for decompressed data */ 753 decompbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY, 754 M_NETGRAPH_MPPC, M_NOWAIT); 755 if (decompbuf == NULL) { 756 m_freem(m); 757 free(buf, M_NETGRAPH_MPPC); 758 return (ENOMEM); 759 } 760 decomplen = MPPC_DECOMP_BUFSIZE; 761 762 /* Prepare to decompress */ 763 source = buf; 764 sourceCnt = len; 765 dest = decompbuf; 766 destCnt = decomplen; 767 if ((header & MPPC_FLAG_RESTART) != 0) 768 flags |= MPPC_RESTART_HISTORY; 769 770 /* Decompress */ 771 rtn = MPPC_Decompress(&source, &dest, 772 &sourceCnt, &destCnt, d->history, flags); 773 774 /* Check return value */ 775 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); 776 if ((rtn & MPPC_DEST_EXHAUSTED) != 0 777 || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) { 778 log(LOG_ERR, "%s: decomp returned 0x%x", 779 __func__, rtn); 780 free(buf, M_NETGRAPH_MPPC); 781 free(decompbuf, M_NETGRAPH_MPPC); 782 goto failed; 783 } 784 785 /* Replace compressed data with decompressed data */ 786 free(buf, M_NETGRAPH_MPPC); 787 len = decomplen - destCnt; 788 789 m_freem(m); 790 m = m_devget((caddr_t)decompbuf, len, 0, NULL, NULL); 791 free(decompbuf, M_NETGRAPH_MPPC); 792 } 793 #endif 794 795 /* Return result in an mbuf */ 796 *datap = m; 797 return (*datap == NULL ? ENOBUFS : 0); 798 } 799 800 /* 801 * The peer has sent us a CCP ResetRequest, so reset our transmit state. 802 */ 803 static void 804 ng_mppc_reset_req(node_p node) 805 { 806 const priv_p priv = NG_NODE_PRIVATE(node); 807 struct ng_mppc_dir *const d = &priv->xmit; 808 809 #ifdef NETGRAPH_MPPC_COMPRESSION 810 if (d->history != NULL) 811 MPPC_InitCompressionHistory(d->history); 812 #endif 813 #ifdef NETGRAPH_MPPC_ENCRYPTION 814 if ((d->cfg.bits & MPPE_STATELESS) == 0) 815 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 816 #endif 817 d->flushed = 1; 818 } 819 820 #ifdef NETGRAPH_MPPC_ENCRYPTION 821 /* 822 * Generate a new encryption key 823 */ 824 static void 825 ng_mppc_getkey(const u_char *h, u_char *h2, int len) 826 { 827 static const u_char pad1[40] = 828 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 static const u_char pad2[40] = 833 { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 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 u_char hash[20]; 838 SHA1_CTX c; 839 840 SHA1Init(&c); 841 SHA1Update(&c, h, len); 842 SHA1Update(&c, pad1, sizeof(pad1)); 843 SHA1Update(&c, h2, len); 844 SHA1Update(&c, pad2, sizeof(pad2)); 845 SHA1Final(hash, &c); 846 bcopy(hash, h2, len); 847 } 848 849 /* 850 * Update the encryption key 851 */ 852 static void 853 ng_mppc_updatekey(u_int32_t bits, 854 u_char *key0, u_char *key, struct rc4_state *rc4) 855 { 856 const int keylen = KEYLEN(bits); 857 858 ng_mppc_getkey(key0, key, keylen); 859 rc4_init(rc4, key, keylen); 860 rc4_crypt(rc4, key, key, keylen); 861 if ((bits & MPPE_40) != 0) 862 bcopy(&ng_mppe_weakenkey, key, 3); 863 else if ((bits & MPPE_56) != 0) 864 bcopy(&ng_mppe_weakenkey, key, 1); 865 rc4_init(rc4, key, keylen); 866 } 867 #endif 868 869