1 2 /* 3 * ng_mppc.c 4 * 5 * Copyright (c) 1996-2000 Whistle Communications, Inc. 6 * All rights reserved. 7 * 8 * Subject to the following obligations and disclaimer of warranty, use and 9 * redistribution of this software, in source or object code forms, with or 10 * without modifications are expressly permitted by Whistle Communications; 11 * provided, however, that: 12 * 1. Any and all reproductions of the source or object code must include the 13 * copyright notice above and the following disclaimer of warranties; and 14 * 2. No rights are granted, in any manner or form, to use Whistle 15 * Communications, Inc. trademarks, including the mark "WHISTLE 16 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 17 * such appears in the above copyright notice or in the software. 18 * 19 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 20 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 21 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 22 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 24 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 25 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 26 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 27 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 28 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 29 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 30 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 31 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 35 * OF SUCH DAMAGE. 36 * 37 * Author: Archie Cobbs <archie@freebsd.org> 38 * 39 * $Whistle: ng_mppc.c,v 1.4 1999/11/25 00:10:12 archie Exp $ 40 * $FreeBSD$ 41 */ 42 43 /* 44 * Microsoft PPP compression (MPPC) and encryption (MPPE) netgraph node type. 45 * 46 * You must define one or both of the NETGRAPH_MPPC_COMPRESSION and/or 47 * NETGRAPH_MPPC_ENCRYPTION options for this node type to be useful. 48 */ 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/kernel.h> 53 #include <sys/mbuf.h> 54 #include <sys/malloc.h> 55 #include <sys/errno.h> 56 #include <sys/syslog.h> 57 58 #include <netgraph/ng_message.h> 59 #include <netgraph/netgraph.h> 60 #include <netgraph/ng_mppc.h> 61 62 #include "opt_netgraph.h" 63 64 #if !defined(NETGRAPH_MPPC_COMPRESSION) && !defined(NETGRAPH_MPPC_ENCRYPTION) 65 #error Need either NETGRAPH_MPPC_COMPRESSION or NETGRAPH_MPPC_ENCRYPTION 66 #endif 67 68 #ifdef NG_SEPARATE_MALLOC 69 MALLOC_DEFINE(M_NETGRAPH_MPPC, "netgraph_mppc", "netgraph mppc node "); 70 #else 71 #define M_NETGRAPH_MPPC M_NETGRAPH 72 #endif 73 74 #ifdef NETGRAPH_MPPC_COMPRESSION 75 /* XXX this file doesn't exist yet, but hopefully someday it will... */ 76 #include <net/mppc.h> 77 #endif 78 #ifdef NETGRAPH_MPPC_ENCRYPTION 79 #include <crypto/rc4/rc4.h> 80 #endif 81 #include <crypto/sha1.h> 82 83 /* Decompression blowup */ 84 #define MPPC_DECOMP_BUFSIZE 8092 /* allocate buffer this big */ 85 #define MPPC_DECOMP_SAFETY 100 /* plus this much margin */ 86 87 /* MPPC/MPPE header length */ 88 #define MPPC_HDRLEN 2 89 90 /* Key length */ 91 #define KEYLEN(b) (((b) & MPPE_128) ? 16 : 8) 92 93 /* What sequence number jump is too far */ 94 #define MPPC_INSANE_JUMP 256 95 96 /* MPPC packet header bits */ 97 #define MPPC_FLAG_FLUSHED 0x8000 /* xmitter reset state */ 98 #define MPPC_FLAG_RESTART 0x4000 /* compress history restart */ 99 #define MPPC_FLAG_COMPRESSED 0x2000 /* packet is compresed */ 100 #define MPPC_FLAG_ENCRYPTED 0x1000 /* packet is encrypted */ 101 #define MPPC_CCOUNT_MASK 0x0fff /* sequence number mask */ 102 103 #define MPPE_UPDATE_MASK 0xff /* coherency count when we're */ 104 #define MPPE_UPDATE_FLAG 0xff /* supposed to update key */ 105 106 #define MPPC_COMP_OK 0x05 107 #define MPPC_DECOMP_OK 0x05 108 109 /* Per direction info */ 110 struct ng_mppc_dir { 111 struct ng_mppc_config cfg; /* configuration */ 112 hook_p hook; /* netgraph hook */ 113 u_int16_t cc:12; /* coherency count */ 114 u_char flushed; /* clean history (xmit only) */ 115 #ifdef NETGRAPH_MPPC_COMPRESSION 116 u_char *history; /* compression history */ 117 #endif 118 #ifdef NETGRAPH_MPPC_ENCRYPTION 119 u_char key[MPPE_KEY_LEN]; /* session key */ 120 struct rc4_state rc4; /* rc4 state */ 121 #endif 122 }; 123 124 /* Node private data */ 125 struct ng_mppc_private { 126 struct ng_mppc_dir xmit; /* compress/encrypt config */ 127 struct ng_mppc_dir recv; /* decompress/decrypt config */ 128 ng_ID_t ctrlnode; /* path to controlling node */ 129 }; 130 typedef struct ng_mppc_private *priv_p; 131 132 /* Netgraph node methods */ 133 static ng_constructor_t ng_mppc_constructor; 134 static ng_rcvmsg_t ng_mppc_rcvmsg; 135 static ng_shutdown_t ng_mppc_shutdown; 136 static ng_newhook_t ng_mppc_newhook; 137 static ng_rcvdata_t ng_mppc_rcvdata; 138 static ng_disconnect_t ng_mppc_disconnect; 139 140 /* Helper functions */ 141 static int ng_mppc_compress(node_p node, 142 struct mbuf *m, struct mbuf **resultp); 143 static int ng_mppc_decompress(node_p node, 144 struct mbuf *m, struct mbuf **resultp); 145 static void ng_mppc_getkey(const u_char *h, u_char *h2, int len); 146 static void ng_mppc_updatekey(u_int32_t bits, 147 u_char *key0, u_char *key, struct rc4_state *rc4); 148 static void ng_mppc_reset_req(node_p node); 149 150 /* Node type descriptor */ 151 static struct ng_type ng_mppc_typestruct = { 152 NG_ABI_VERSION, 153 NG_MPPC_NODE_TYPE, 154 NULL, 155 ng_mppc_constructor, 156 ng_mppc_rcvmsg, 157 ng_mppc_shutdown, 158 ng_mppc_newhook, 159 NULL, 160 NULL, 161 ng_mppc_rcvdata, 162 ng_mppc_disconnect, 163 NULL 164 }; 165 NETGRAPH_INIT(mppc, &ng_mppc_typestruct); 166 167 /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */ 168 static const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e }; 169 170 #define ERROUT(x) do { error = (x); goto done; } while (0) 171 172 /************************************************************************ 173 NETGRAPH NODE STUFF 174 ************************************************************************/ 175 176 /* 177 * Node type constructor 178 */ 179 static int 180 ng_mppc_constructor(node_p node) 181 { 182 priv_p priv; 183 184 /* Allocate private structure */ 185 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH_MPPC, M_NOWAIT | M_ZERO); 186 if (priv == NULL) 187 return (ENOMEM); 188 189 NG_NODE_SET_PRIVATE(node, priv); 190 191 /* Done */ 192 return (0); 193 } 194 195 /* 196 * Give our OK for a hook to be added 197 */ 198 static int 199 ng_mppc_newhook(node_p node, hook_p hook, const char *name) 200 { 201 const priv_p priv = NG_NODE_PRIVATE(node); 202 hook_p *hookPtr; 203 204 /* Check hook name */ 205 if (strcmp(name, NG_MPPC_HOOK_COMP) == 0) 206 hookPtr = &priv->xmit.hook; 207 else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0) 208 hookPtr = &priv->recv.hook; 209 else 210 return (EINVAL); 211 212 /* See if already connected */ 213 if (*hookPtr != NULL) 214 return (EISCONN); 215 216 /* OK */ 217 *hookPtr = hook; 218 return (0); 219 } 220 221 /* 222 * Receive a control message 223 */ 224 static int 225 ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook) 226 { 227 const priv_p priv = NG_NODE_PRIVATE(node); 228 struct ng_mesg *resp = NULL; 229 int error = 0; 230 struct ng_mesg *msg; 231 232 NGI_GET_MSG(item, msg); 233 switch (msg->header.typecookie) { 234 case NGM_MPPC_COOKIE: 235 switch (msg->header.cmd) { 236 case NGM_MPPC_CONFIG_COMP: 237 case NGM_MPPC_CONFIG_DECOMP: 238 { 239 struct ng_mppc_config *const cfg 240 = (struct ng_mppc_config *)msg->data; 241 const int isComp = 242 msg->header.cmd == NGM_MPPC_CONFIG_COMP; 243 struct ng_mppc_dir *const d = isComp ? 244 &priv->xmit : &priv->recv; 245 246 /* Check configuration */ 247 if (msg->header.arglen != sizeof(*cfg)) 248 ERROUT(EINVAL); 249 if (cfg->enable) { 250 if ((cfg->bits & ~MPPC_VALID_BITS) != 0) 251 ERROUT(EINVAL); 252 #ifndef NETGRAPH_MPPC_COMPRESSION 253 if ((cfg->bits & MPPC_BIT) != 0) 254 ERROUT(EPROTONOSUPPORT); 255 #endif 256 #ifndef NETGRAPH_MPPC_ENCRYPTION 257 if ((cfg->bits & MPPE_BITS) != 0) 258 ERROUT(EPROTONOSUPPORT); 259 #endif 260 } else 261 cfg->bits = 0; 262 263 /* Save return address so we can send reset-req's */ 264 priv->ctrlnode = NGI_RETADDR(item); 265 266 /* Configuration is OK, reset to it */ 267 d->cfg = *cfg; 268 269 #ifdef NETGRAPH_MPPC_COMPRESSION 270 /* Initialize state buffers for compression */ 271 if (d->history != NULL) { 272 FREE(d->history, M_NETGRAPH_MPPC); 273 d->history = NULL; 274 } 275 if ((cfg->bits & MPPC_BIT) != 0) { 276 MALLOC(d->history, u_char *, 277 isComp ? MPPC_SizeOfCompressionHistory() : 278 MPPC_SizeOfDecompressionHistory(), 279 M_NETGRAPH_MPPC, M_NOWAIT); 280 if (d->history == NULL) 281 ERROUT(ENOMEM); 282 if (isComp) 283 MPPC_InitCompressionHistory(d->history); 284 else { 285 MPPC_InitDecompressionHistory( 286 d->history); 287 } 288 } 289 #endif 290 291 #ifdef NETGRAPH_MPPC_ENCRYPTION 292 /* Generate initial session keys for encryption */ 293 if ((cfg->bits & MPPE_BITS) != 0) { 294 const int keylen = KEYLEN(cfg->bits); 295 296 bcopy(cfg->startkey, d->key, keylen); 297 ng_mppc_getkey(cfg->startkey, d->key, keylen); 298 if ((cfg->bits & MPPE_40) != 0) 299 bcopy(&ng_mppe_weakenkey, d->key, 3); 300 else if ((cfg->bits & MPPE_56) != 0) 301 bcopy(&ng_mppe_weakenkey, d->key, 1); 302 rc4_init(&d->rc4, d->key, keylen); 303 } 304 #endif 305 306 /* Initialize other state */ 307 d->cc = 0; 308 d->flushed = 0; 309 break; 310 } 311 312 case NGM_MPPC_RESETREQ: 313 ng_mppc_reset_req(node); 314 break; 315 316 default: 317 error = EINVAL; 318 break; 319 } 320 break; 321 default: 322 error = EINVAL; 323 break; 324 } 325 done: 326 NG_RESPOND_MSG(error, node, item, resp); 327 NG_FREE_MSG(msg); 328 return (error); 329 } 330 331 /* 332 * Receive incoming data on our hook. 333 */ 334 static int 335 ng_mppc_rcvdata(hook_p hook, item_p item) 336 { 337 const node_p node = NG_HOOK_NODE(hook); 338 const priv_p priv = NG_NODE_PRIVATE(node); 339 struct mbuf *out; 340 int error; 341 struct mbuf *m; 342 343 NGI_GET_M(item, m); 344 /* Compress and/or encrypt */ 345 if (hook == priv->xmit.hook) { 346 if (!priv->xmit.cfg.enable) { 347 NG_FREE_M(m); 348 NG_FREE_ITEM(item); 349 return (ENXIO); 350 } 351 if ((error = ng_mppc_compress(node, m, &out)) != 0) { 352 NG_FREE_M(m); 353 NG_FREE_ITEM(item); 354 return(error); 355 } 356 NG_FREE_M(m); 357 NG_FWD_NEW_DATA(error, item, priv->xmit.hook, out); 358 return (error); 359 } 360 361 /* Decompress and/or decrypt */ 362 if (hook == priv->recv.hook) { 363 if (!priv->recv.cfg.enable) { 364 NG_FREE_M(m); 365 NG_FREE_ITEM(item); 366 return (ENXIO); 367 } 368 if ((error = ng_mppc_decompress(node, m, &out)) != 0) { 369 NG_FREE_M(m); 370 NG_FREE_ITEM(item); 371 if (error == EINVAL && priv->ctrlnode != 0) { 372 struct ng_mesg *msg; 373 374 /* Need to send a reset-request */ 375 NG_MKMESSAGE(msg, NGM_MPPC_COOKIE, 376 NGM_MPPC_RESETREQ, 0, M_NOWAIT); 377 if (msg == NULL) 378 return (error); 379 NG_SEND_MSG_ID(error, node, msg, 380 priv->ctrlnode, 0); 381 } 382 return (error); 383 } 384 NG_FREE_M(m); 385 NG_FWD_NEW_DATA(error, item, priv->recv.hook, out); 386 return (error); 387 } 388 389 /* Oops */ 390 panic("%s: unknown hook", __func__); 391 #ifdef RESTARTABLE_PANICS 392 return (EINVAL); 393 #endif 394 } 395 396 /* 397 * Destroy node 398 */ 399 static int 400 ng_mppc_shutdown(node_p node) 401 { 402 const priv_p priv = NG_NODE_PRIVATE(node); 403 404 /* Take down netgraph node */ 405 #ifdef NETGRAPH_MPPC_COMPRESSION 406 if (priv->xmit.history != NULL) 407 FREE(priv->xmit.history, M_NETGRAPH_MPPC); 408 if (priv->recv.history != NULL) 409 FREE(priv->recv.history, M_NETGRAPH_MPPC); 410 #endif 411 bzero(priv, sizeof(*priv)); 412 FREE(priv, M_NETGRAPH_MPPC); 413 NG_NODE_SET_PRIVATE(node, NULL); 414 NG_NODE_UNREF(node); /* let the node escape */ 415 return (0); 416 } 417 418 /* 419 * Hook disconnection 420 */ 421 static int 422 ng_mppc_disconnect(hook_p hook) 423 { 424 const node_p node = NG_HOOK_NODE(hook); 425 const priv_p priv = NG_NODE_PRIVATE(node); 426 427 /* Zero out hook pointer */ 428 if (hook == priv->xmit.hook) 429 priv->xmit.hook = NULL; 430 if (hook == priv->recv.hook) 431 priv->recv.hook = NULL; 432 433 /* Go away if no longer connected */ 434 if ((NG_NODE_NUMHOOKS(node) == 0) 435 && NG_NODE_IS_VALID(node)) 436 ng_rmnode_self(node); 437 return (0); 438 } 439 440 /************************************************************************ 441 HELPER STUFF 442 ************************************************************************/ 443 444 /* 445 * Compress/encrypt a packet and put the result in a new mbuf at *resultp. 446 * The original mbuf is not free'd. 447 */ 448 static int 449 ng_mppc_compress(node_p node, struct mbuf *m, struct mbuf **resultp) 450 { 451 const priv_p priv = NG_NODE_PRIVATE(node); 452 struct ng_mppc_dir *const d = &priv->xmit; 453 u_char *inbuf, *outbuf; 454 int outlen, inlen; 455 u_int16_t header; 456 457 /* Initialize */ 458 *resultp = NULL; 459 header = d->cc; 460 if (d->flushed) { 461 header |= MPPC_FLAG_FLUSHED; 462 d->flushed = 0; 463 } 464 465 /* Work with contiguous regions of memory */ 466 inlen = m->m_pkthdr.len; 467 MALLOC(inbuf, u_char *, inlen, M_NETGRAPH_MPPC, M_NOWAIT); 468 if (inbuf == NULL) 469 return (ENOMEM); 470 m_copydata(m, 0, inlen, (caddr_t)inbuf); 471 if ((d->cfg.bits & MPPC_BIT) != 0) 472 outlen = MPPC_MAX_BLOWUP(inlen); 473 else 474 outlen = MPPC_HDRLEN + inlen; 475 MALLOC(outbuf, u_char *, outlen, M_NETGRAPH_MPPC, M_NOWAIT); 476 if (outbuf == NULL) { 477 FREE(inbuf, M_NETGRAPH_MPPC); 478 return (ENOMEM); 479 } 480 481 /* Compress "inbuf" into "outbuf" (if compression enabled) */ 482 #ifdef NETGRAPH_MPPC_COMPRESSION 483 if ((d->cfg.bits & MPPC_BIT) != 0) { 484 u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS; 485 u_char *source, *dest; 486 u_long sourceCnt, destCnt; 487 int rtn; 488 489 /* Prepare to compress */ 490 source = inbuf; 491 sourceCnt = inlen; 492 dest = outbuf + MPPC_HDRLEN; 493 destCnt = outlen - MPPC_HDRLEN; 494 if ((d->cfg.bits & MPPE_STATELESS) == 0) 495 flags |= MPPC_SAVE_HISTORY; 496 497 /* Compress */ 498 rtn = MPPC_Compress(&source, &dest, &sourceCnt, 499 &destCnt, d->history, flags, 0); 500 501 /* Check return value */ 502 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); 503 if ((rtn & MPPC_EXPANDED) == 0 504 && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) { 505 outlen -= destCnt; 506 header |= MPPC_FLAG_COMPRESSED; 507 if ((rtn & MPPC_RESTART_HISTORY) != 0) 508 header |= MPPC_FLAG_RESTART; 509 } 510 d->flushed = (rtn & MPPC_EXPANDED) != 0 511 || (flags & MPPC_SAVE_HISTORY) == 0; 512 } 513 #endif 514 515 /* If we did not compress this packet, copy it to output buffer */ 516 if ((header & MPPC_FLAG_COMPRESSED) == 0) { 517 bcopy(inbuf, outbuf + MPPC_HDRLEN, inlen); 518 outlen = MPPC_HDRLEN + inlen; 519 } 520 FREE(inbuf, M_NETGRAPH_MPPC); 521 522 /* Always set the flushed bit in stateless mode */ 523 if ((d->cfg.bits & MPPE_STATELESS) != 0) 524 header |= MPPC_FLAG_FLUSHED; 525 526 /* Now encrypt packet (if encryption enabled) */ 527 #ifdef NETGRAPH_MPPC_ENCRYPTION 528 if ((d->cfg.bits & MPPE_BITS) != 0) { 529 530 /* Set header bits; need to reset key if we say we did */ 531 header |= MPPC_FLAG_ENCRYPTED; 532 if ((header & MPPC_FLAG_FLUSHED) != 0) 533 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 534 535 /* Update key if it's time */ 536 if ((d->cfg.bits & MPPE_STATELESS) != 0 537 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) { 538 ng_mppc_updatekey(d->cfg.bits, 539 d->cfg.startkey, d->key, &d->rc4); 540 } 541 542 /* Encrypt packet */ 543 rc4_crypt(&d->rc4, outbuf + MPPC_HDRLEN, 544 outbuf + MPPC_HDRLEN, outlen - MPPC_HDRLEN); 545 } 546 #endif 547 548 /* Update sequence number */ 549 d->cc++; 550 551 /* Install header */ 552 *((u_int16_t *)outbuf) = htons(header); 553 554 /* Return packet in an mbuf */ 555 *resultp = m_devget((caddr_t)outbuf, outlen, 0, NULL, NULL); 556 FREE(outbuf, M_NETGRAPH_MPPC); 557 return (*resultp == NULL ? ENOBUFS : 0); 558 } 559 560 /* 561 * Decompress/decrypt packet and put the result in a new mbuf at *resultp. 562 * The original mbuf is not free'd. 563 */ 564 static int 565 ng_mppc_decompress(node_p node, struct mbuf *m, struct mbuf **resultp) 566 { 567 const priv_p priv = NG_NODE_PRIVATE(node); 568 struct ng_mppc_dir *const d = &priv->recv; 569 u_int16_t header, cc, numLost; 570 u_char *buf; 571 int len; 572 573 /* Pull off header */ 574 if (m->m_pkthdr.len < MPPC_HDRLEN) 575 return (EINVAL); 576 m_copydata(m, 0, MPPC_HDRLEN, (caddr_t)&header); 577 header = ntohs(header); 578 cc = (header & MPPC_CCOUNT_MASK); 579 580 /* Copy payload into a contiguous region of memory */ 581 len = m->m_pkthdr.len - MPPC_HDRLEN; 582 MALLOC(buf, u_char *, len, M_NETGRAPH_MPPC, M_NOWAIT); 583 if (buf == NULL) 584 return (ENOMEM); 585 m_copydata(m, MPPC_HDRLEN, len, (caddr_t)buf); 586 587 /* Check for insane jumps in sequence numbering (D.O.S. attack) */ 588 numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK); 589 if (numLost >= MPPC_INSANE_JUMP) { 590 log(LOG_ERR, "%s: insane jump %d", __func__, numLost); 591 priv->recv.cfg.enable = 0; 592 goto failed; 593 } 594 595 /* If flushed bit set, we can always handle packet */ 596 if ((header & MPPC_FLAG_FLUSHED) != 0) { 597 #ifdef NETGRAPH_MPPC_COMPRESSION 598 if (d->history != NULL) 599 MPPC_InitDecompressionHistory(d->history); 600 #endif 601 #ifdef NETGRAPH_MPPC_ENCRYPTION 602 if ((d->cfg.bits & MPPE_BITS) != 0) { 603 604 /* Resync as necessary, skipping lost packets */ 605 while (d->cc != cc) { 606 if ((d->cfg.bits & MPPE_STATELESS) 607 || (d->cc & MPPE_UPDATE_MASK) 608 == MPPE_UPDATE_FLAG) { 609 ng_mppc_updatekey(d->cfg.bits, 610 d->cfg.startkey, d->key, &d->rc4); 611 } 612 d->cc++; 613 } 614 615 /* Reset key (except in stateless mode, see below) */ 616 if ((d->cfg.bits & MPPE_STATELESS) == 0) 617 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 618 } 619 #endif 620 d->cc = cc; /* skip over lost seq numbers */ 621 numLost = 0; /* act like no packets were lost */ 622 } 623 624 /* Can't decode non-sequential packets without a flushed bit */ 625 if (numLost != 0) 626 goto failed; 627 628 /* Decrypt packet */ 629 if ((header & MPPC_FLAG_ENCRYPTED) != 0) { 630 631 /* Are we not expecting encryption? */ 632 if ((d->cfg.bits & MPPE_BITS) == 0) { 633 log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 634 __func__, "encrypted"); 635 goto failed; 636 } 637 638 #ifdef NETGRAPH_MPPC_ENCRYPTION 639 /* Update key if it's time (always in stateless mode) */ 640 if ((d->cfg.bits & MPPE_STATELESS) != 0 641 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) { 642 ng_mppc_updatekey(d->cfg.bits, 643 d->cfg.startkey, d->key, &d->rc4); 644 } 645 646 /* Decrypt packet */ 647 rc4_crypt(&d->rc4, buf, buf, len); 648 #endif 649 } else { 650 651 /* Are we expecting encryption? */ 652 if ((d->cfg.bits & MPPE_BITS) != 0) { 653 log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 654 __func__, "unencrypted"); 655 goto failed; 656 } 657 } 658 659 /* Update coherency count for next time (12 bit arithmetic) */ 660 d->cc++; 661 662 /* Check for unexpected compressed packet */ 663 if ((header & MPPC_FLAG_COMPRESSED) != 0 664 && (d->cfg.bits & MPPC_BIT) == 0) { 665 log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 666 __func__, "compressed"); 667 failed: 668 FREE(buf, M_NETGRAPH_MPPC); 669 return (EINVAL); 670 } 671 672 #ifdef NETGRAPH_MPPC_COMPRESSION 673 /* Decompress packet */ 674 if ((header & MPPC_FLAG_COMPRESSED) != 0) { 675 int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS; 676 u_char *decompbuf, *source, *dest; 677 u_long sourceCnt, destCnt; 678 int decomplen, rtn; 679 680 /* Allocate a buffer for decompressed data */ 681 MALLOC(decompbuf, u_char *, MPPC_DECOMP_BUFSIZE 682 + MPPC_DECOMP_SAFETY, M_NETGRAPH_MPPC, M_NOWAIT); 683 if (decompbuf == NULL) { 684 FREE(buf, M_NETGRAPH_MPPC); 685 return (ENOMEM); 686 } 687 decomplen = MPPC_DECOMP_BUFSIZE; 688 689 /* Prepare to decompress */ 690 source = buf; 691 sourceCnt = len; 692 dest = decompbuf; 693 destCnt = decomplen; 694 if ((header & MPPC_FLAG_RESTART) != 0) 695 flags |= MPPC_RESTART_HISTORY; 696 697 /* Decompress */ 698 rtn = MPPC_Decompress(&source, &dest, 699 &sourceCnt, &destCnt, d->history, flags); 700 701 /* Check return value */ 702 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); 703 if ((rtn & MPPC_DEST_EXHAUSTED) != 0 704 || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) { 705 log(LOG_ERR, "%s: decomp returned 0x%x", 706 __func__, rtn); 707 FREE(decompbuf, M_NETGRAPH_MPPC); 708 goto failed; 709 } 710 711 /* Replace compressed data with decompressed data */ 712 FREE(buf, M_NETGRAPH_MPPC); 713 buf = decompbuf; 714 len = decomplen - destCnt; 715 } 716 #endif 717 718 /* Return result in an mbuf */ 719 *resultp = m_devget((caddr_t)buf, len, 0, NULL, NULL); 720 FREE(buf, M_NETGRAPH_MPPC); 721 return (*resultp == NULL ? ENOBUFS : 0); 722 } 723 724 /* 725 * The peer has sent us a CCP ResetRequest, so reset our transmit state. 726 */ 727 static void 728 ng_mppc_reset_req(node_p node) 729 { 730 const priv_p priv = NG_NODE_PRIVATE(node); 731 struct ng_mppc_dir *const d = &priv->xmit; 732 733 #ifdef NETGRAPH_MPPC_COMPRESSION 734 if (d->history != NULL) 735 MPPC_InitCompressionHistory(d->history); 736 #endif 737 #ifdef NETGRAPH_MPPC_ENCRYPTION 738 if ((d->cfg.bits & MPPE_STATELESS) == 0) 739 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 740 #endif 741 d->flushed = 1; 742 } 743 744 /* 745 * Generate a new encryption key 746 */ 747 static void 748 ng_mppc_getkey(const u_char *h, u_char *h2, int len) 749 { 750 static const u_char pad1[10] = 751 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; 752 static const u_char pad2[10] = 753 { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, }; 754 u_char hash[20]; 755 SHA1_CTX c; 756 int k; 757 758 bzero(&hash, sizeof(hash)); 759 SHA1Init(&c); 760 SHA1Update(&c, h, len); 761 for (k = 0; k < 4; k++) 762 SHA1Update(&c, pad1, sizeof(pad2)); 763 SHA1Update(&c, h2, len); 764 for (k = 0; k < 4; k++) 765 SHA1Update(&c, pad2, sizeof(pad2)); 766 SHA1Final(hash, &c); 767 bcopy(hash, h2, len); 768 } 769 770 /* 771 * Update the encryption key 772 */ 773 static void 774 ng_mppc_updatekey(u_int32_t bits, 775 u_char *key0, u_char *key, struct rc4_state *rc4) 776 { 777 const int keylen = KEYLEN(bits); 778 779 ng_mppc_getkey(key0, key, keylen); 780 rc4_init(rc4, key, keylen); 781 rc4_crypt(rc4, key, key, keylen); 782 if ((bits & MPPE_40) != 0) 783 bcopy(&ng_mppe_weakenkey, key, 3); 784 else if ((bits & MPPE_56) != 0) 785 bcopy(&ng_mppe_weakenkey, key, 1); 786 rc4_init(rc4, key, keylen); 787 } 788 789