xref: /freebsd/sys/netgraph/ng_mppc.c (revision b077aed33b7b6aefca7b17ddb250cf521f938613)
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 		/* Are we expecting encryption? */
738 		if ((d->cfg.bits & MPPE_BITS) != 0) {
739 			log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
740 				__func__, "unencrypted");
741 			goto failed;
742 		}
743 	}
744 
745 	/* Update coherency count for next time (12 bit arithmetic) */
746 	MPPC_CCOUNT_INC(d->cc);
747 
748 	/* Check for unexpected compressed packet */
749 	if ((header & MPPC_FLAG_COMPRESSED) != 0
750 	    && (d->cfg.bits & MPPC_BIT) == 0) {
751 		log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
752 			__func__, "compressed");
753 failed:
754 		m_freem(m);
755 		return (EINVAL);
756 	}
757 
758 #ifdef NETGRAPH_MPPC_COMPRESSION
759 	/* Decompress packet */
760 	if ((header & MPPC_FLAG_COMPRESSED) != 0) {
761 		int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS;
762 		u_char *inbuf, *outbuf;
763 		int inlen, outlen, ina;
764 		u_char *source, *dest;
765 		u_long sourceCnt, destCnt;
766 		int rtn;
767 
768 		/* Copy payload into a contiguous region of memory. */
769 		inlen = m->m_pkthdr.len;
770 		if (m->m_next == NULL) {
771                 	inbuf = mtod(m, u_char *);
772 			ina = 0;
773 		} else {
774 		        inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
775 			if (inbuf == NULL) {
776 				m_freem(m);
777 				return (ENOMEM);
778 			}
779 			m_copydata(m, 0, inlen, (caddr_t)inbuf);
780 			ina = 1;
781 		}
782 
783 		/* Allocate a buffer for decompressed data */
784 		outbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY,
785 		    M_NETGRAPH_MPPC, M_NOWAIT);
786 		if (outbuf == NULL) {
787 			m_freem(m);
788 			if (ina)
789 				free(inbuf, M_NETGRAPH_MPPC);
790 			return (ENOMEM);
791 		}
792 		outlen = MPPC_DECOMP_BUFSIZE;
793 
794 		/* Prepare to decompress */
795 		source = inbuf;
796 		sourceCnt = inlen;
797 		dest = outbuf;
798 		destCnt = outlen;
799 		if ((header & MPPC_FLAG_RESTART) != 0)
800 			flags |= MPPC_RESTART_HISTORY;
801 
802 		/* Decompress */
803 		rtn = MPPC_Decompress(&source, &dest,
804 			&sourceCnt, &destCnt, d->history, flags);
805 
806 		/* Check return value */
807 		/* KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); */
808 		if ((rtn & MPPC_DEST_EXHAUSTED) != 0
809 		    || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) {
810 			log(LOG_ERR, "%s: decomp returned 0x%x",
811 			    __func__, rtn);
812 			if (ina)
813 				free(inbuf, M_NETGRAPH_MPPC);
814 			free(outbuf, M_NETGRAPH_MPPC);
815 			goto failed;
816 		}
817 
818 		/* Replace compressed data with decompressed data */
819 		if (ina)
820 			free(inbuf, M_NETGRAPH_MPPC);
821 		outlen -= destCnt;
822 
823 		m_copyback(m, 0, outlen, (caddr_t)outbuf);
824 		if (m->m_pkthdr.len < outlen) {
825 			m_freem(m);
826 			m = NULL;
827 		} else if (outlen < m->m_pkthdr.len)
828 			m_adj(m, outlen - m->m_pkthdr.len);
829 		free(outbuf, M_NETGRAPH_MPPC);
830 	}
831 #endif
832 
833 	/* Return result in an mbuf */
834 	*datap = m;
835 	return (*datap == NULL ? ENOBUFS : 0);
836 }
837 
838 /*
839  * The peer has sent us a CCP ResetRequest, so reset our transmit state.
840  */
841 static void
842 ng_mppc_reset_req(node_p node)
843 {
844 	const priv_p priv = NG_NODE_PRIVATE(node);
845 	struct ng_mppc_dir *const d = &priv->xmit;
846 
847 #ifdef NETGRAPH_MPPC_COMPRESSION
848 	if (d->history != NULL)
849 		MPPC_InitCompressionHistory(d->history);
850 #endif
851 #ifdef NETGRAPH_MPPC_ENCRYPTION
852 	if ((d->cfg.bits & MPPE_STATELESS) == 0)
853 		rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
854 #endif
855 	d->flushed = 1;
856 }
857 
858 #ifdef NETGRAPH_MPPC_ENCRYPTION
859 /*
860  * Generate a new encryption key
861  */
862 static void
863 ng_mppc_getkey(const u_char *h, u_char *h2, int len)
864 {
865 	static const u_char pad1[40] =
866 	    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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 	static const u_char pad2[40] =
871 	    { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
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 	u_char hash[20];
876 	SHA1_CTX c;
877 
878 	SHA1Init(&c);
879 	SHA1Update(&c, h, len);
880 	SHA1Update(&c, pad1, sizeof(pad1));
881 	SHA1Update(&c, h2, len);
882 	SHA1Update(&c, pad2, sizeof(pad2));
883 	SHA1Final(hash, &c);
884 	bcopy(hash, h2, len);
885 }
886 
887 /*
888  * Update the encryption key
889  */
890 static void
891 ng_mppc_updatekey(u_int32_t bits,
892 	u_char *key0, u_char *key, struct rc4_state *rc4)
893 {
894 	const int keylen = KEYLEN(bits);
895 
896 	ng_mppc_getkey(key0, key, keylen);
897 	rc4_init(rc4, key, keylen);
898 	rc4_crypt(rc4, key, key, keylen);
899 	if ((bits & MPPE_40) != 0)
900 		bcopy(&ng_mppe_weakenkey, key, 3);
901 	else if ((bits & MPPE_56) != 0)
902 		bcopy(&ng_mppe_weakenkey, key, 1);
903 	rc4_init(rc4, key, keylen);
904 }
905 #endif
906