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: src/sys/netgraph/ng_mppc.c,v 1.31 2007/05/18 15:28:01 mav Exp $ 42 * $DragonFly: src/sys/netgraph7/ng_mppc.c,v 1.2 2008/06/26 23:05:35 dillon Exp $ 43 */ 44 45 /* 46 * Microsoft PPP compression (MPPC) and encryption (MPPE) netgraph node type. 47 * 48 * You must define one or both of the NETGRAPH_MPPC_COMPRESSION and/or 49 * NETGRAPH_MPPC_ENCRYPTION options for this node type to be useful. 50 */ 51 52 #include <sys/param.h> 53 #include <sys/systm.h> 54 #include <sys/kernel.h> 55 #include <sys/mbuf.h> 56 #include <sys/malloc.h> 57 #include <sys/errno.h> 58 #include <sys/syslog.h> 59 60 #include <netgraph7/ng_message.h> 61 #include <netgraph7/netgraph.h> 62 #include "ng_mppc.h" 63 64 #include "opt_netgraph.h" 65 66 #if !defined(NETGRAPH7_MPPC_COMPRESSION) && !defined(NETGRAPH7_MPPC_ENCRYPTION) 67 #ifdef KLD_MODULE 68 /* XXX NETGRAPH7_MPPC_COMPRESSION isn't functional yet */ 69 #define NETGRAPH7_MPPC_ENCRYPTION 70 #else 71 /* This case is indicative of an error in sys/conf files */ 72 #error Need either NETGRAPH7_MPPC_COMPRESSION or NETGRAPH7_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 NETGRAPH7_MPPC_COMPRESSION 83 /* XXX this file doesn't exist yet, but hopefully someday it will... */ 84 #include <net/mppc.h> 85 #endif 86 #ifdef NETGRAPH7_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 NETGRAPH7_MPPC_COMPRESSION 132 u_char *history; /* compression history */ 133 #endif 134 #ifdef NETGRAPH7_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 NETGRAPH7_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 NETGRAPH7_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 = kmalloc(sizeof(*priv), M_NETGRAPH_MPPC, 205 M_WAITOK | M_NULLOK | M_ZERO); 206 if (priv == NULL) 207 return (ENOMEM); 208 209 NG_NODE_SET_PRIVATE(node, priv); 210 211 /* This node is not thread safe. */ 212 NG_NODE_FORCE_WRITER(node); 213 214 /* Done */ 215 return (0); 216 } 217 218 /* 219 * Give our OK for a hook to be added 220 */ 221 static int 222 ng_mppc_newhook(node_p node, hook_p hook, const char *name) 223 { 224 const priv_p priv = NG_NODE_PRIVATE(node); 225 hook_p *hookPtr; 226 227 /* Check hook name */ 228 if (strcmp(name, NG_MPPC_HOOK_COMP) == 0) 229 hookPtr = &priv->xmit.hook; 230 else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0) 231 hookPtr = &priv->recv.hook; 232 else 233 return (EINVAL); 234 235 /* See if already connected */ 236 if (*hookPtr != NULL) 237 return (EISCONN); 238 239 /* OK */ 240 *hookPtr = hook; 241 return (0); 242 } 243 244 /* 245 * Receive a control message 246 */ 247 static int 248 ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook) 249 { 250 const priv_p priv = NG_NODE_PRIVATE(node); 251 struct ng_mesg *resp = NULL; 252 int error = 0; 253 struct ng_mesg *msg; 254 255 NGI_GET_MSG(item, msg); 256 switch (msg->header.typecookie) { 257 case NGM_MPPC_COOKIE: 258 switch (msg->header.cmd) { 259 case NGM_MPPC_CONFIG_COMP: 260 case NGM_MPPC_CONFIG_DECOMP: 261 { 262 struct ng_mppc_config *const cfg 263 = (struct ng_mppc_config *)msg->data; 264 const int isComp = 265 msg->header.cmd == NGM_MPPC_CONFIG_COMP; 266 struct ng_mppc_dir *const d = isComp ? 267 &priv->xmit : &priv->recv; 268 269 /* Check configuration */ 270 if (msg->header.arglen != sizeof(*cfg)) 271 ERROUT(EINVAL); 272 if (cfg->enable) { 273 if ((cfg->bits & ~MPPC_VALID_BITS) != 0) 274 ERROUT(EINVAL); 275 #ifndef NETGRAPH7_MPPC_COMPRESSION 276 if ((cfg->bits & MPPC_BIT) != 0) 277 ERROUT(EPROTONOSUPPORT); 278 #endif 279 #ifndef NETGRAPH7_MPPC_ENCRYPTION 280 if ((cfg->bits & MPPE_BITS) != 0) 281 ERROUT(EPROTONOSUPPORT); 282 #endif 283 } else 284 cfg->bits = 0; 285 286 /* Save return address so we can send reset-req's */ 287 if (!isComp) 288 priv->ctrlnode = NGI_RETADDR(item); 289 290 /* Configuration is OK, reset to it */ 291 d->cfg = *cfg; 292 293 #ifdef NETGRAPH7_MPPC_COMPRESSION 294 /* Initialize state buffers for compression */ 295 if (d->history != NULL) { 296 kfree(d->history, M_NETGRAPH_MPPC); 297 d->history = NULL; 298 } 299 if ((cfg->bits & MPPC_BIT) != 0) { 300 d->history = kmalloc(isComp ? MPPC_SizeOfCompressionHistory() : MPPC_SizeOfDecompressionHistory(), 301 M_NETGRAPH_MPPC, 302 M_WAITOK | M_NULLOK); 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 NETGRAPH7_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_WAITOK | M_NULLOK); 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 NETGRAPH7_MPPC_COMPRESSION 424 if (priv->xmit.history != NULL) 425 kfree(priv->xmit.history, M_NETGRAPH_MPPC); 426 if (priv->recv.history != NULL) 427 kfree(priv->recv.history, M_NETGRAPH_MPPC); 428 #endif 429 bzero(priv, sizeof(*priv)); 430 kfree(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 /* 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 NETGRAPH7_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; 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 inbuf = kmalloc(inlen, M_NETGRAPH_MPPC, M_WAITOK | M_NULLOK); 496 if (inbuf == NULL) { 497 m_freem(m); 498 return (ENOMEM); 499 } 500 m_copydata(m, 0, inlen, (caddr_t)inbuf); 501 502 outlen = MPPC_MAX_BLOWUP(inlen); 503 outbuf = kmalloc(outlen, M_NETGRAPH_MPPC, M_WAITOK | M_NULLOK); 504 if (outbuf == NULL) { 505 m_freem(m); 506 kfree(inbuf, M_NETGRAPH_MPPC); 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 kfree(inbuf, M_NETGRAPH_MPPC); 539 kfree(outbuf, M_NETGRAPH_MPPC); 540 541 /* Check m_devget() result. */ 542 if (m == NULL) 543 return (ENOMEM); 544 } 545 #endif 546 547 /* Now encrypt packet (if encryption enabled) */ 548 #ifdef NETGRAPH7_MPPC_ENCRYPTION 549 if ((d->cfg.bits & MPPE_BITS) != 0) { 550 struct mbuf *m1; 551 552 /* Set header bits */ 553 header |= MPPC_FLAG_ENCRYPTED; 554 555 /* Update key if it's time */ 556 if ((d->cfg.bits & MPPE_STATELESS) != 0 557 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) { 558 ng_mppc_updatekey(d->cfg.bits, 559 d->cfg.startkey, d->key, &d->rc4); 560 } else if ((header & MPPC_FLAG_FLUSHED) != 0) { 561 /* Need to reset key if we say we did 562 and ng_mppc_updatekey wasn't called to do it also. */ 563 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 564 } 565 566 /* We must own the mbuf chain exclusively to modify it. */ 567 m = m_unshare(m, MB_DONTWAIT); 568 if (m == NULL) 569 return (ENOMEM); 570 571 /* Encrypt packet */ 572 m1 = m; 573 while (m1) { 574 rc4_crypt(&d->rc4, mtod(m1, u_char *), 575 mtod(m1, u_char *), m1->m_len); 576 m1 = m1->m_next; 577 } 578 } 579 #endif 580 581 /* Update coherency count for next time (12 bit arithmetic) */ 582 MPPC_CCOUNT_INC(d->cc); 583 584 /* Install header */ 585 M_PREPEND(m, MPPC_HDRLEN, MB_DONTWAIT); 586 if (m != NULL) 587 *(mtod(m, uint16_t *)) = htons(header); 588 589 *datap = m; 590 return (*datap == NULL ? ENOBUFS : 0); 591 } 592 593 /* 594 * Decompress/decrypt packet and put the result in a new mbuf at *resultp. 595 * The original mbuf is not free'd. 596 */ 597 static int 598 ng_mppc_decompress(node_p node, struct mbuf **datap) 599 { 600 const priv_p priv = NG_NODE_PRIVATE(node); 601 struct ng_mppc_dir *const d = &priv->recv; 602 u_int16_t header, cc; 603 u_int numLost; 604 struct mbuf *m = *datap; 605 606 /* Pull off header */ 607 if (m->m_pkthdr.len < MPPC_HDRLEN) { 608 m_freem(m); 609 return (EINVAL); 610 } 611 m_copydata(m, 0, MPPC_HDRLEN, (caddr_t)&header); 612 header = ntohs(header); 613 cc = (header & MPPC_CCOUNT_MASK); 614 m_adj(m, MPPC_HDRLEN); 615 616 /* Check for an unexpected jump in the sequence number */ 617 numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK); 618 619 /* If flushed bit set, we can always handle packet */ 620 if ((header & MPPC_FLAG_FLUSHED) != 0) { 621 #ifdef NETGRAPH7_MPPC_COMPRESSION 622 if (d->history != NULL) 623 MPPC_InitDecompressionHistory(d->history); 624 #endif 625 #ifdef NETGRAPH7_MPPC_ENCRYPTION 626 if ((d->cfg.bits & MPPE_BITS) != 0) { 627 u_int rekey; 628 629 /* How many times are we going to have to re-key? */ 630 rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ? 631 numLost : (numLost / (MPPE_UPDATE_MASK + 1)); 632 if (rekey > MPPE_MAX_REKEY) { 633 log(LOG_ERR, "%s: too many (%d) packets" 634 " dropped, disabling node %p!", 635 __func__, numLost, node); 636 priv->recv.cfg.enable = 0; 637 goto failed; 638 } 639 640 /* Re-key as necessary to catch up to peer */ 641 while (d->cc != cc) { 642 if ((d->cfg.bits & MPPE_STATELESS) != 0 643 || (d->cc & MPPE_UPDATE_MASK) 644 == MPPE_UPDATE_FLAG) { 645 ng_mppc_updatekey(d->cfg.bits, 646 d->cfg.startkey, d->key, &d->rc4); 647 } 648 MPPC_CCOUNT_INC(d->cc); 649 } 650 651 /* Reset key (except in stateless mode, see below) */ 652 if ((d->cfg.bits & MPPE_STATELESS) == 0) 653 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 654 } 655 #endif 656 d->cc = cc; /* skip over lost seq numbers */ 657 numLost = 0; /* act like no packets were lost */ 658 } 659 660 /* Can't decode non-sequential packets without a flushed bit */ 661 if (numLost != 0) 662 goto failed; 663 664 /* Decrypt packet */ 665 if ((header & MPPC_FLAG_ENCRYPTED) != 0) { 666 #ifdef NETGRAPH7_MPPC_ENCRYPTION 667 struct mbuf *m1; 668 #endif 669 670 /* Are we not expecting encryption? */ 671 if ((d->cfg.bits & MPPE_BITS) == 0) { 672 log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 673 __func__, "encrypted"); 674 goto failed; 675 } 676 677 #ifdef NETGRAPH7_MPPC_ENCRYPTION 678 /* Update key if it's time (always in stateless mode) */ 679 if ((d->cfg.bits & MPPE_STATELESS) != 0 680 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) { 681 ng_mppc_updatekey(d->cfg.bits, 682 d->cfg.startkey, d->key, &d->rc4); 683 } 684 685 /* We must own the mbuf chain exclusively to modify it. */ 686 m = m_unshare(m, MB_DONTWAIT); 687 if (m == NULL) 688 return (ENOMEM); 689 690 /* Decrypt packet */ 691 m1 = m; 692 while (m1 != NULL) { 693 rc4_crypt(&d->rc4, mtod(m1, u_char *), 694 mtod(m1, u_char *), m1->m_len); 695 m1 = m1->m_next; 696 } 697 #endif 698 } else { 699 700 /* Are we expecting encryption? */ 701 if ((d->cfg.bits & MPPE_BITS) != 0) { 702 log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 703 __func__, "unencrypted"); 704 goto failed; 705 } 706 } 707 708 /* Update coherency count for next time (12 bit arithmetic) */ 709 MPPC_CCOUNT_INC(d->cc); 710 711 /* Check for unexpected compressed packet */ 712 if ((header & MPPC_FLAG_COMPRESSED) != 0 713 && (d->cfg.bits & MPPC_BIT) == 0) { 714 log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 715 __func__, "compressed"); 716 failed: 717 m_freem(m); 718 return (EINVAL); 719 } 720 721 #ifdef NETGRAPH7_MPPC_COMPRESSION 722 /* Decompress packet */ 723 if ((header & MPPC_FLAG_COMPRESSED) != 0) { 724 int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS; 725 u_char *decompbuf, *source, *dest; 726 u_long sourceCnt, destCnt; 727 int decomplen, rtn; 728 u_char *buf; 729 int len; 730 731 /* Copy payload into a contiguous region of memory. */ 732 len = m->m_pkthdr.len; 733 buf = kmalloc(len, M_NETGRAPH_MPPC, M_WAITOK | M_NULLOK); 734 if (buf == NULL) { 735 m_freem(m); 736 return (ENOMEM); 737 } 738 m_copydata(m, 0, len, (caddr_t)buf); 739 740 /* Allocate a buffer for decompressed data */ 741 decompbuf = kmalloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY, 742 M_NETGRAPH_MPPC, M_WAITOK | M_NULLOK); 743 if (decompbuf == NULL) { 744 m_freem(m); 745 kfree(buf, M_NETGRAPH_MPPC); 746 return (ENOMEM); 747 } 748 decomplen = MPPC_DECOMP_BUFSIZE; 749 750 /* Prepare to decompress */ 751 source = buf; 752 sourceCnt = len; 753 dest = decompbuf; 754 destCnt = decomplen; 755 if ((header & MPPC_FLAG_RESTART) != 0) 756 flags |= MPPC_RESTART_HISTORY; 757 758 /* Decompress */ 759 rtn = MPPC_Decompress(&source, &dest, 760 &sourceCnt, &destCnt, d->history, flags); 761 762 /* Check return value */ 763 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); 764 if ((rtn & MPPC_DEST_EXHAUSTED) != 0 765 || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) { 766 log(LOG_ERR, "%s: decomp returned 0x%x", 767 __func__, rtn); 768 kfree(buf, M_NETGRAPH_MPPC); 769 kfree(decompbuf, M_NETGRAPH_MPPC); 770 goto failed; 771 } 772 773 /* Replace compressed data with decompressed data */ 774 kfree(buf, M_NETGRAPH_MPPC); 775 len = decomplen - destCnt; 776 777 m_freem(m); 778 m = m_devget((caddr_t)decompbuf, len, 0, NULL, NULL); 779 kfree(decompbuf, M_NETGRAPH_MPPC); 780 } 781 #endif 782 783 /* Return result in an mbuf */ 784 *datap = m; 785 return (*datap == NULL ? ENOBUFS : 0); 786 } 787 788 /* 789 * The peer has sent us a CCP ResetRequest, so reset our transmit state. 790 */ 791 static void 792 ng_mppc_reset_req(node_p node) 793 { 794 const priv_p priv = NG_NODE_PRIVATE(node); 795 struct ng_mppc_dir *const d = &priv->xmit; 796 797 #ifdef NETGRAPH7_MPPC_COMPRESSION 798 if (d->history != NULL) 799 MPPC_InitCompressionHistory(d->history); 800 #endif 801 #ifdef NETGRAPH7_MPPC_ENCRYPTION 802 if ((d->cfg.bits & MPPE_STATELESS) == 0) 803 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 804 #endif 805 d->flushed = 1; 806 } 807 808 #ifdef NETGRAPH7_MPPC_ENCRYPTION 809 /* 810 * Generate a new encryption key 811 */ 812 static void 813 ng_mppc_getkey(const u_char *h, u_char *h2, int len) 814 { 815 static const u_char pad1[10] = 816 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; 817 static const u_char pad2[10] = 818 { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, }; 819 u_char hash[20]; 820 SHA1_CTX c; 821 int k; 822 823 SHA1Init(&c); 824 SHA1Update(&c, h, len); 825 for (k = 0; k < 4; k++) 826 SHA1Update(&c, pad1, sizeof(pad1)); 827 SHA1Update(&c, h2, len); 828 for (k = 0; k < 4; k++) 829 SHA1Update(&c, pad2, sizeof(pad2)); 830 SHA1Final(hash, &c); 831 bcopy(hash, h2, len); 832 } 833 834 /* 835 * Update the encryption key 836 */ 837 static void 838 ng_mppc_updatekey(u_int32_t bits, 839 u_char *key0, u_char *key, struct rc4_state *rc4) 840 { 841 const int keylen = KEYLEN(bits); 842 843 ng_mppc_getkey(key0, key, keylen); 844 rc4_init(rc4, key, keylen); 845 rc4_crypt(rc4, key, key, keylen); 846 if ((bits & MPPE_40) != 0) 847 bcopy(&ng_mppe_weakenkey, key, 3); 848 else if ((bits & MPPE_56) != 0) 849 bcopy(&ng_mppe_weakenkey, key, 1); 850 rc4_init(rc4, key, keylen); 851 } 852 #endif 853 854