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