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
78static 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
111SYSCTL_NODE(_net_graph, OID_AUTO, mppe, CTLFLAG_RW, 0, "MPPE");
112
113static int mppe_block_on_max_rekey = 0;
114TUNABLE_INT("net.graph.mppe.block_on_max_rekey", &mppe_block_on_max_rekey);
115SYSCTL_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
118static int mppe_log_max_rekey = 1;
119TUNABLE_INT("net.graph.mppe.log_max_rekey", &mppe_log_max_rekey);
120SYSCTL_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
123static int mppe_max_rekey = MPPE_MAX_REKEY;
124TUNABLE_INT("net.graph.mppe.max_rekey", &mppe_max_rekey);
125SYSCTL_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 */
144struct 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 */
159struct 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};
164typedef struct ng_mppc_private *priv_p;
165
166/* Netgraph node methods */
167static ng_constructor_t	ng_mppc_constructor;
168static ng_rcvmsg_t	ng_mppc_rcvmsg;
169static ng_shutdown_t	ng_mppc_shutdown;
170static ng_newhook_t	ng_mppc_newhook;
171static ng_rcvdata_t	ng_mppc_rcvdata;
172static ng_disconnect_t	ng_mppc_disconnect;
173
174/* Helper functions */
175static int	ng_mppc_compress(node_p node,
176			struct mbuf **datap);
177static int	ng_mppc_decompress(node_p node,
178			struct mbuf **datap);
179#ifdef NETGRAPH_MPPC_ENCRYPTION
180static void	ng_mppc_getkey(const u_char *h, u_char *h2, int len);
181static void	ng_mppc_updatekey(u_int32_t bits,
182			u_char *key0, u_char *key, struct rc4_state *rc4);
183#endif
184static void	ng_mppc_reset_req(node_p node);
185
186/* Node type descriptor */
187static 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};
197NETGRAPH_INIT(mppc, &ng_mppc_typestruct);
198
199#ifdef NETGRAPH_MPPC_ENCRYPTION
200/* Depend on separate rc4 module */
201MODULE_DEPEND(ng_mppc, rc4, 1, 1, 1);
202#endif
203
204/* Fixed bit pattern to weaken keysize down to 40 or 56 bits */
205static 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 */
216static int
217ng_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 */
236static int
237ng_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 */
262static int
263ng_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	}
364done:
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 */
373static int
374ng_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 */
430static int
431ng_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 */
452static int
453ng_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 */
479static int
480ng_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_DONTWAIT);
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);
529err1:
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_DONTWAIT);
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 */
628static int
629ng_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_DONTWAIT);
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");
757failed:
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 */
845static void
846ng_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 */
866static void
867ng_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 */
894static void
895ng_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