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