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