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_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 #ifdef RESTARTABLE_PANICS 408 return (EINVAL); 409 #endif 410 } 411 412 /* 413 * Destroy node 414 */ 415 static int 416 ng_mppc_shutdown(node_p node) 417 { 418 const priv_p priv = NG_NODE_PRIVATE(node); 419 420 /* Take down netgraph node */ 421 #ifdef NETGRAPH_MPPC_COMPRESSION 422 if (priv->xmit.history != NULL) 423 free(priv->xmit.history, M_NETGRAPH_MPPC); 424 if (priv->recv.history != NULL) 425 free(priv->recv.history, M_NETGRAPH_MPPC); 426 #endif 427 bzero(priv, sizeof(*priv)); 428 free(priv, M_NETGRAPH_MPPC); 429 NG_NODE_SET_PRIVATE(node, NULL); 430 NG_NODE_UNREF(node); /* let the node escape */ 431 return (0); 432 } 433 434 /* 435 * Hook disconnection 436 */ 437 static int 438 ng_mppc_disconnect(hook_p hook) 439 { 440 const node_p node = NG_HOOK_NODE(hook); 441 const priv_p priv = NG_NODE_PRIVATE(node); 442 443 /* Zero out hook pointer */ 444 if (hook == priv->xmit.hook) 445 priv->xmit.hook = NULL; 446 if (hook == priv->recv.hook) 447 priv->recv.hook = NULL; 448 449 /* Go away if no longer connected */ 450 if ((NG_NODE_NUMHOOKS(node) == 0) 451 && NG_NODE_IS_VALID(node)) 452 ng_rmnode_self(node); 453 return (0); 454 } 455 456 /************************************************************************ 457 HELPER STUFF 458 ************************************************************************/ 459 460 /* 461 * Compress/encrypt a packet and put the result in a new mbuf at *resultp. 462 * The original mbuf is not free'd. 463 */ 464 static int 465 ng_mppc_compress(node_p node, struct mbuf **datap) 466 { 467 const priv_p priv = NG_NODE_PRIVATE(node); 468 struct ng_mppc_dir *const d = &priv->xmit; 469 u_int16_t header; 470 struct mbuf *m = *datap; 471 472 /* We must own the mbuf chain exclusively to modify it. */ 473 m = m_unshare(m, M_DONTWAIT); 474 if (m == NULL) 475 return (ENOMEM); 476 477 /* Initialize */ 478 header = d->cc; 479 480 /* Always set the flushed bit in stateless mode */ 481 if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) { 482 header |= MPPC_FLAG_FLUSHED; 483 d->flushed = 0; 484 } 485 486 /* Compress packet (if compression enabled) */ 487 #ifdef NETGRAPH_MPPC_COMPRESSION 488 if ((d->cfg.bits & MPPC_BIT) != 0) { 489 u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS; 490 u_char *inbuf, *outbuf; 491 int outlen, inlen, ina; 492 u_char *source, *dest; 493 u_long sourceCnt, destCnt; 494 int rtn; 495 496 /* Work with contiguous regions of memory. */ 497 inlen = m->m_pkthdr.len; 498 if (m->m_next == NULL) { 499 inbuf = mtod(m, u_char *); 500 ina = 0; 501 } else { 502 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT); 503 if (inbuf == NULL) 504 goto err1; 505 m_copydata(m, 0, inlen, (caddr_t)inbuf); 506 ina = 1; 507 } 508 509 outlen = MPPC_MAX_BLOWUP(inlen); 510 outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT); 511 if (outbuf == NULL) { 512 if (ina) 513 free(inbuf, M_NETGRAPH_MPPC); 514 err1: 515 m_freem(m); 516 MPPC_InitCompressionHistory(d->history); 517 d->flushed = 1; 518 return (ENOMEM); 519 } 520 521 /* Prepare to compress */ 522 source = inbuf; 523 sourceCnt = inlen; 524 dest = outbuf; 525 destCnt = outlen; 526 if ((d->cfg.bits & MPPE_STATELESS) == 0) 527 flags |= MPPC_SAVE_HISTORY; 528 529 /* Compress */ 530 rtn = MPPC_Compress(&source, &dest, &sourceCnt, 531 &destCnt, d->history, flags, 0); 532 533 /* Check return value */ 534 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); 535 if ((rtn & MPPC_EXPANDED) == 0 536 && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) { 537 outlen -= destCnt; 538 header |= MPPC_FLAG_COMPRESSED; 539 if ((rtn & MPPC_RESTART_HISTORY) != 0) 540 header |= MPPC_FLAG_RESTART; 541 542 /* Replace m by the compresed one. */ 543 m_copyback(m, 0, outlen, (caddr_t)outbuf); 544 if (m->m_pkthdr.len < outlen) { 545 m_freem(m); 546 m = NULL; 547 } else if (outlen < m->m_pkthdr.len) 548 m_adj(m, outlen - m->m_pkthdr.len); 549 } 550 d->flushed = (rtn & MPPC_EXPANDED) != 0 551 || (flags & MPPC_SAVE_HISTORY) == 0; 552 553 if (ina) 554 free(inbuf, M_NETGRAPH_MPPC); 555 free(outbuf, M_NETGRAPH_MPPC); 556 557 /* Check mbuf chain reload result. */ 558 if (m == NULL) { 559 if (!d->flushed) { 560 MPPC_InitCompressionHistory(d->history); 561 d->flushed = 1; 562 } 563 return (ENOMEM); 564 } 565 } 566 #endif 567 568 /* Now encrypt packet (if encryption enabled) */ 569 #ifdef NETGRAPH_MPPC_ENCRYPTION 570 if ((d->cfg.bits & MPPE_BITS) != 0) { 571 struct mbuf *m1; 572 573 /* Set header bits */ 574 header |= MPPC_FLAG_ENCRYPTED; 575 576 /* Update key if it's time */ 577 if ((d->cfg.bits & MPPE_STATELESS) != 0 578 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) { 579 ng_mppc_updatekey(d->cfg.bits, 580 d->cfg.startkey, d->key, &d->rc4); 581 } else if ((header & MPPC_FLAG_FLUSHED) != 0) { 582 /* Need to reset key if we say we did 583 and ng_mppc_updatekey wasn't called to do it also. */ 584 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 585 } 586 587 /* Encrypt packet */ 588 m1 = m; 589 while (m1) { 590 rc4_crypt(&d->rc4, mtod(m1, u_char *), 591 mtod(m1, u_char *), m1->m_len); 592 m1 = m1->m_next; 593 } 594 } 595 #endif 596 597 /* Update coherency count for next time (12 bit arithmetic) */ 598 MPPC_CCOUNT_INC(d->cc); 599 600 /* Install header */ 601 M_PREPEND(m, MPPC_HDRLEN, M_DONTWAIT); 602 if (m != NULL) 603 be16enc(mtod(m, void *), header); 604 605 *datap = m; 606 return (*datap == NULL ? ENOBUFS : 0); 607 } 608 609 /* 610 * Decompress/decrypt packet and put the result in a new mbuf at *resultp. 611 * The original mbuf is not free'd. 612 */ 613 static int 614 ng_mppc_decompress(node_p node, struct mbuf **datap) 615 { 616 const priv_p priv = NG_NODE_PRIVATE(node); 617 struct ng_mppc_dir *const d = &priv->recv; 618 u_int16_t header, cc; 619 u_int numLost; 620 struct mbuf *m = *datap; 621 622 /* We must own the mbuf chain exclusively to modify it. */ 623 m = m_unshare(m, M_DONTWAIT); 624 if (m == NULL) 625 return (ENOMEM); 626 627 /* Pull off header */ 628 if (m->m_pkthdr.len < MPPC_HDRLEN) { 629 m_freem(m); 630 return (EINVAL); 631 } 632 header = be16dec(mtod(m, void *)); 633 cc = (header & MPPC_CCOUNT_MASK); 634 m_adj(m, MPPC_HDRLEN); 635 636 /* Check for an unexpected jump in the sequence number */ 637 numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK); 638 639 /* If flushed bit set, we can always handle packet */ 640 if ((header & MPPC_FLAG_FLUSHED) != 0) { 641 #ifdef NETGRAPH_MPPC_COMPRESSION 642 if (d->history != NULL) 643 MPPC_InitDecompressionHistory(d->history); 644 #endif 645 #ifdef NETGRAPH_MPPC_ENCRYPTION 646 if ((d->cfg.bits & MPPE_BITS) != 0) { 647 u_int rekey; 648 649 /* How many times are we going to have to re-key? */ 650 rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ? 651 numLost : (numLost / (MPPE_UPDATE_MASK + 1)); 652 if (rekey > MPPE_MAX_REKEY) { 653 log(LOG_ERR, "%s: too many (%d) packets" 654 " dropped, disabling node %p!", 655 __func__, numLost, node); 656 priv->recv.cfg.enable = 0; 657 goto failed; 658 } 659 660 /* Re-key as necessary to catch up to peer */ 661 while (d->cc != cc) { 662 if ((d->cfg.bits & MPPE_STATELESS) != 0 663 || (d->cc & MPPE_UPDATE_MASK) 664 == MPPE_UPDATE_FLAG) { 665 ng_mppc_updatekey(d->cfg.bits, 666 d->cfg.startkey, d->key, &d->rc4); 667 } 668 MPPC_CCOUNT_INC(d->cc); 669 } 670 671 /* Reset key (except in stateless mode, see below) */ 672 if ((d->cfg.bits & MPPE_STATELESS) == 0) 673 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 674 } 675 #endif 676 d->cc = cc; /* skip over lost seq numbers */ 677 numLost = 0; /* act like no packets were lost */ 678 } 679 680 /* Can't decode non-sequential packets without a flushed bit */ 681 if (numLost != 0) 682 goto failed; 683 684 /* Decrypt packet */ 685 if ((header & MPPC_FLAG_ENCRYPTED) != 0) { 686 #ifdef NETGRAPH_MPPC_ENCRYPTION 687 struct mbuf *m1; 688 #endif 689 690 /* Are we not expecting encryption? */ 691 if ((d->cfg.bits & MPPE_BITS) == 0) { 692 log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 693 __func__, "encrypted"); 694 goto failed; 695 } 696 697 #ifdef NETGRAPH_MPPC_ENCRYPTION 698 /* Update key if it's time (always in stateless mode) */ 699 if ((d->cfg.bits & MPPE_STATELESS) != 0 700 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) { 701 ng_mppc_updatekey(d->cfg.bits, 702 d->cfg.startkey, d->key, &d->rc4); 703 } 704 705 /* Decrypt packet */ 706 m1 = m; 707 while (m1 != NULL) { 708 rc4_crypt(&d->rc4, mtod(m1, u_char *), 709 mtod(m1, u_char *), m1->m_len); 710 m1 = m1->m_next; 711 } 712 #endif 713 } else { 714 715 /* Are we expecting encryption? */ 716 if ((d->cfg.bits & MPPE_BITS) != 0) { 717 log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 718 __func__, "unencrypted"); 719 goto failed; 720 } 721 } 722 723 /* Update coherency count for next time (12 bit arithmetic) */ 724 MPPC_CCOUNT_INC(d->cc); 725 726 /* Check for unexpected compressed packet */ 727 if ((header & MPPC_FLAG_COMPRESSED) != 0 728 && (d->cfg.bits & MPPC_BIT) == 0) { 729 log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 730 __func__, "compressed"); 731 failed: 732 m_freem(m); 733 return (EINVAL); 734 } 735 736 #ifdef NETGRAPH_MPPC_COMPRESSION 737 /* Decompress packet */ 738 if ((header & MPPC_FLAG_COMPRESSED) != 0) { 739 int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS; 740 u_char *inbuf, *outbuf; 741 int inlen, outlen, ina; 742 u_char *source, *dest; 743 u_long sourceCnt, destCnt; 744 int rtn; 745 746 /* Copy payload into a contiguous region of memory. */ 747 inlen = m->m_pkthdr.len; 748 if (m->m_next == NULL) { 749 inbuf = mtod(m, u_char *); 750 ina = 0; 751 } else { 752 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT); 753 if (inbuf == NULL) { 754 m_freem(m); 755 return (ENOMEM); 756 } 757 m_copydata(m, 0, inlen, (caddr_t)inbuf); 758 ina = 1; 759 } 760 761 /* Allocate a buffer for decompressed data */ 762 outbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY, 763 M_NETGRAPH_MPPC, M_NOWAIT); 764 if (outbuf == NULL) { 765 m_freem(m); 766 if (ina) 767 free(inbuf, M_NETGRAPH_MPPC); 768 return (ENOMEM); 769 } 770 outlen = MPPC_DECOMP_BUFSIZE; 771 772 /* Prepare to decompress */ 773 source = inbuf; 774 sourceCnt = inlen; 775 dest = outbuf; 776 destCnt = outlen; 777 if ((header & MPPC_FLAG_RESTART) != 0) 778 flags |= MPPC_RESTART_HISTORY; 779 780 /* Decompress */ 781 rtn = MPPC_Decompress(&source, &dest, 782 &sourceCnt, &destCnt, d->history, flags); 783 784 /* Check return value */ 785 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); 786 if ((rtn & MPPC_DEST_EXHAUSTED) != 0 787 || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) { 788 log(LOG_ERR, "%s: decomp returned 0x%x", 789 __func__, rtn); 790 if (ina) 791 free(inbuf, M_NETGRAPH_MPPC); 792 free(outbuf, M_NETGRAPH_MPPC); 793 goto failed; 794 } 795 796 /* Replace compressed data with decompressed data */ 797 if (ina) 798 free(inbuf, M_NETGRAPH_MPPC); 799 outlen -= destCnt; 800 801 m_copyback(m, 0, outlen, (caddr_t)outbuf); 802 if (m->m_pkthdr.len < outlen) { 803 m_freem(m); 804 m = NULL; 805 } else if (outlen < m->m_pkthdr.len) 806 m_adj(m, outlen - m->m_pkthdr.len); 807 free(outbuf, M_NETGRAPH_MPPC); 808 } 809 #endif 810 811 /* Return result in an mbuf */ 812 *datap = m; 813 return (*datap == NULL ? ENOBUFS : 0); 814 } 815 816 /* 817 * The peer has sent us a CCP ResetRequest, so reset our transmit state. 818 */ 819 static void 820 ng_mppc_reset_req(node_p node) 821 { 822 const priv_p priv = NG_NODE_PRIVATE(node); 823 struct ng_mppc_dir *const d = &priv->xmit; 824 825 #ifdef NETGRAPH_MPPC_COMPRESSION 826 if (d->history != NULL) 827 MPPC_InitCompressionHistory(d->history); 828 #endif 829 #ifdef NETGRAPH_MPPC_ENCRYPTION 830 if ((d->cfg.bits & MPPE_STATELESS) == 0) 831 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 832 #endif 833 d->flushed = 1; 834 } 835 836 #ifdef NETGRAPH_MPPC_ENCRYPTION 837 /* 838 * Generate a new encryption key 839 */ 840 static void 841 ng_mppc_getkey(const u_char *h, u_char *h2, int len) 842 { 843 static const u_char pad1[40] = 844 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 845 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 846 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 847 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 848 static const u_char pad2[40] = 849 { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 850 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 851 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 852 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2 }; 853 u_char hash[20]; 854 SHA1_CTX c; 855 856 SHA1Init(&c); 857 SHA1Update(&c, h, len); 858 SHA1Update(&c, pad1, sizeof(pad1)); 859 SHA1Update(&c, h2, len); 860 SHA1Update(&c, pad2, sizeof(pad2)); 861 SHA1Final(hash, &c); 862 bcopy(hash, h2, len); 863 } 864 865 /* 866 * Update the encryption key 867 */ 868 static void 869 ng_mppc_updatekey(u_int32_t bits, 870 u_char *key0, u_char *key, struct rc4_state *rc4) 871 { 872 const int keylen = KEYLEN(bits); 873 874 ng_mppc_getkey(key0, key, keylen); 875 rc4_init(rc4, key, keylen); 876 rc4_crypt(rc4, key, key, keylen); 877 if ((bits & MPPE_40) != 0) 878 bcopy(&ng_mppe_weakenkey, key, 3); 879 else if ((bits & MPPE_56) != 0) 880 bcopy(&ng_mppe_weakenkey, key, 1); 881 rc4_init(rc4, key, keylen); 882 } 883 #endif 884 885