159109Sarchie/*
259109Sarchie * ng_mppc.c
3139823Simp */
4139823Simp
5139823Simp/*-
659109Sarchie * Copyright (c) 1996-2000 Whistle Communications, Inc.
759109Sarchie * All rights reserved.
859109Sarchie *
959109Sarchie * Subject to the following obligations and disclaimer of warranty, use and
1059109Sarchie * redistribution of this software, in source or object code forms, with or
1159109Sarchie * without modifications are expressly permitted by Whistle Communications;
1259109Sarchie * provided, however, that:
1359109Sarchie * 1. Any and all reproductions of the source or object code must include the
1459109Sarchie *    copyright notice above and the following disclaimer of warranties; and
1559109Sarchie * 2. No rights are granted, in any manner or form, to use Whistle
1659109Sarchie *    Communications, Inc. trademarks, including the mark "WHISTLE
1759109Sarchie *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
1859109Sarchie *    such appears in the above copyright notice or in the software.
1959109Sarchie *
2059109Sarchie * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
2159109Sarchie * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
2259109Sarchie * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
2359109Sarchie * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
2459109Sarchie * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
2559109Sarchie * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
2659109Sarchie * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
2759109Sarchie * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
2859109Sarchie * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
2959109Sarchie * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
3059109Sarchie * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
3159109Sarchie * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
3259109Sarchie * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
3359109Sarchie * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3459109Sarchie * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3559109Sarchie * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
3659109Sarchie * OF SUCH DAMAGE.
3759109Sarchie *
3867506Sjulian * Author: Archie Cobbs <archie@freebsd.org>
3959109Sarchie *
4059109Sarchie * $Whistle: ng_mppc.c,v 1.4 1999/11/25 00:10:12 archie Exp $
4159109Sarchie * $FreeBSD$
4259109Sarchie */
4359109Sarchie
4459109Sarchie/*
4559109Sarchie * Microsoft PPP compression (MPPC) and encryption (MPPE) netgraph node type.
4659109Sarchie *
4759109Sarchie * You must define one or both of the NETGRAPH_MPPC_COMPRESSION and/or
4859109Sarchie * NETGRAPH_MPPC_ENCRYPTION options for this node type to be useful.
4959109Sarchie */
5059109Sarchie
5159109Sarchie#include <sys/param.h>
5259109Sarchie#include <sys/systm.h>
5359109Sarchie#include <sys/kernel.h>
5459109Sarchie#include <sys/mbuf.h>
5559109Sarchie#include <sys/malloc.h>
56206021Smav#include <sys/endian.h>
5759109Sarchie#include <sys/errno.h>
58267094Smav#include <sys/sysctl.h>
5959109Sarchie#include <sys/syslog.h>
6059109Sarchie
6159109Sarchie#include <netgraph/ng_message.h>
6259109Sarchie#include <netgraph/netgraph.h>
6359109Sarchie#include <netgraph/ng_mppc.h>
6459109Sarchie
6559109Sarchie#include "opt_netgraph.h"
6659109Sarchie
6759109Sarchie#if !defined(NETGRAPH_MPPC_COMPRESSION) && !defined(NETGRAPH_MPPC_ENCRYPTION)
68151349Syar#ifdef KLD_MODULE
69151349Syar/* XXX NETGRAPH_MPPC_COMPRESSION isn't functional yet */
70151349Syar#define NETGRAPH_MPPC_ENCRYPTION
71151349Syar#else
72151349Syar/* This case is indicative of an error in sys/conf files */
7359109Sarchie#error Need either NETGRAPH_MPPC_COMPRESSION or NETGRAPH_MPPC_ENCRYPTION
7459109Sarchie#endif
75151349Syar#endif
7659109Sarchie
7770870Sjulian#ifdef NG_SEPARATE_MALLOC
78249132Smavstatic MALLOC_DEFINE(M_NETGRAPH_MPPC, "netgraph_mppc", "netgraph mppc node");
7970870Sjulian#else
8070870Sjulian#define M_NETGRAPH_MPPC M_NETGRAPH
8170870Sjulian#endif
8270870Sjulian
8359109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION
8459109Sarchie/* XXX this file doesn't exist yet, but hopefully someday it will... */
8559109Sarchie#include <net/mppc.h>
8659109Sarchie#endif
8759109Sarchie#ifdef NETGRAPH_MPPC_ENCRYPTION
8859109Sarchie#include <crypto/rc4/rc4.h>
8959109Sarchie#endif
9059109Sarchie#include <crypto/sha1.h>
9159109Sarchie
9259109Sarchie/* Decompression blowup */
9359109Sarchie#define MPPC_DECOMP_BUFSIZE	8092            /* allocate buffer this big */
9459109Sarchie#define MPPC_DECOMP_SAFETY	100             /*   plus this much margin */
9559109Sarchie
9659109Sarchie/* MPPC/MPPE header length */
9759109Sarchie#define MPPC_HDRLEN		2
9859109Sarchie
9959109Sarchie/* Key length */
10059109Sarchie#define KEYLEN(b)		(((b) & MPPE_128) ? 16 : 8)
10159109Sarchie
102107845Sarchie/*
103107845Sarchie * When packets are lost with MPPE, we may have to re-key arbitrarily
104107845Sarchie * many times to 'catch up' to the new jumped-ahead sequence number.
105107845Sarchie * Since this can be expensive, we pose a limit on how many re-keyings
106107845Sarchie * we will do at one time to avoid a possible D.O.S. vulnerability.
107107845Sarchie * This should instead be a configurable parameter.
108107845Sarchie */
109107845Sarchie#define MPPE_MAX_REKEY		1000
11059109Sarchie
111267094SmavSYSCTL_NODE(_net_graph, OID_AUTO, mppe, CTLFLAG_RW, 0, "MPPE");
112267094Smav
113267094Smavstatic int mppe_block_on_max_rekey = 0;
114267094SmavTUNABLE_INT("net.graph.mppe.block_on_max_rekey", &mppe_block_on_max_rekey);
115267094SmavSYSCTL_INT(_net_graph_mppe, OID_AUTO, block_on_max_rekey, CTLFLAG_RW,
116267094Smav    &mppe_block_on_max_rekey, 0, "Block node on max MPPE key re-calculations");
117267094Smav
118267094Smavstatic int mppe_log_max_rekey = 1;
119267094SmavTUNABLE_INT("net.graph.mppe.log_max_rekey", &mppe_log_max_rekey);
120267094SmavSYSCTL_INT(_net_graph_mppe, OID_AUTO, log_max_rekey, CTLFLAG_RW,
121267094Smav    &mppe_log_max_rekey, 0, "Log max MPPE key re-calculations event");
122267094Smav
123267094Smavstatic int mppe_max_rekey = MPPE_MAX_REKEY;
124267094SmavTUNABLE_INT("net.graph.mppe.max_rekey", &mppe_max_rekey);
125267094SmavSYSCTL_INT(_net_graph_mppe, OID_AUTO, max_rekey, CTLFLAG_RW,
126267094Smav    &mppe_max_rekey, 0, "Maximum number of MPPE key re-calculations");
127267094Smav
12859109Sarchie/* MPPC packet header bits */
12959109Sarchie#define MPPC_FLAG_FLUSHED	0x8000		/* xmitter reset state */
13059109Sarchie#define MPPC_FLAG_RESTART	0x4000		/* compress history restart */
13159109Sarchie#define MPPC_FLAG_COMPRESSED	0x2000		/* packet is compresed */
13259109Sarchie#define MPPC_FLAG_ENCRYPTED	0x1000		/* packet is encrypted */
13359109Sarchie#define MPPC_CCOUNT_MASK	0x0fff		/* sequence number mask */
13459109Sarchie
135169261Smav#define MPPC_CCOUNT_INC(d)	((d) = (((d) + 1) & MPPC_CCOUNT_MASK))
136169261Smav
13759109Sarchie#define MPPE_UPDATE_MASK	0xff		/* coherency count when we're */
13859109Sarchie#define MPPE_UPDATE_FLAG	0xff		/*   supposed to update key */
13959109Sarchie
14059109Sarchie#define MPPC_COMP_OK		0x05
14159109Sarchie#define MPPC_DECOMP_OK		0x05
14259109Sarchie
14359109Sarchie/* Per direction info */
14459109Sarchiestruct ng_mppc_dir {
14559109Sarchie	struct ng_mppc_config	cfg;		/* configuration */
14659109Sarchie	hook_p			hook;		/* netgraph hook */
14759109Sarchie	u_int16_t		cc:12;		/* coherency count */
14859109Sarchie	u_char			flushed;	/* clean history (xmit only) */
14959109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION
15059109Sarchie	u_char			*history;	/* compression history */
15159109Sarchie#endif
15259109Sarchie#ifdef NETGRAPH_MPPC_ENCRYPTION
15359109Sarchie	u_char			key[MPPE_KEY_LEN];	/* session key */
15459109Sarchie	struct rc4_state	rc4;			/* rc4 state */
15559109Sarchie#endif
15659109Sarchie};
15759109Sarchie
15859109Sarchie/* Node private data */
15959109Sarchiestruct ng_mppc_private {
16059109Sarchie	struct ng_mppc_dir	xmit;		/* compress/encrypt config */
16159109Sarchie	struct ng_mppc_dir	recv;		/* decompress/decrypt config */
16270700Sjulian	ng_ID_t			ctrlnode;	/* path to controlling node */
16359109Sarchie};
16459109Sarchietypedef struct ng_mppc_private *priv_p;
16559109Sarchie
16659109Sarchie/* Netgraph node methods */
16759109Sarchiestatic ng_constructor_t	ng_mppc_constructor;
16859109Sarchiestatic ng_rcvmsg_t	ng_mppc_rcvmsg;
16970700Sjulianstatic ng_shutdown_t	ng_mppc_shutdown;
17059109Sarchiestatic ng_newhook_t	ng_mppc_newhook;
17159109Sarchiestatic ng_rcvdata_t	ng_mppc_rcvdata;
17259109Sarchiestatic ng_disconnect_t	ng_mppc_disconnect;
17359109Sarchie
17459109Sarchie/* Helper functions */
17559109Sarchiestatic int	ng_mppc_compress(node_p node,
176169474Smav			struct mbuf **datap);
17759109Sarchiestatic int	ng_mppc_decompress(node_p node,
178169474Smav			struct mbuf **datap);
179169678Smav#ifdef NETGRAPH_MPPC_ENCRYPTION
18059109Sarchiestatic void	ng_mppc_getkey(const u_char *h, u_char *h2, int len);
18159109Sarchiestatic void	ng_mppc_updatekey(u_int32_t bits,
18259109Sarchie			u_char *key0, u_char *key, struct rc4_state *rc4);
183169678Smav#endif
18459109Sarchiestatic void	ng_mppc_reset_req(node_p node);
18559109Sarchie
18659109Sarchie/* Node type descriptor */
18759109Sarchiestatic struct ng_type ng_mppc_typestruct = {
188129823Sjulian	.version =	NG_ABI_VERSION,
189129823Sjulian	.name =		NG_MPPC_NODE_TYPE,
190129823Sjulian	.constructor =	ng_mppc_constructor,
191129823Sjulian	.rcvmsg =	ng_mppc_rcvmsg,
192129823Sjulian	.shutdown =	ng_mppc_shutdown,
193129823Sjulian	.newhook =	ng_mppc_newhook,
194129823Sjulian	.rcvdata =	ng_mppc_rcvdata,
195129823Sjulian	.disconnect =	ng_mppc_disconnect,
19659109Sarchie};
19759109SarchieNETGRAPH_INIT(mppc, &ng_mppc_typestruct);
19859109Sarchie
199110409Sambrisko#ifdef NETGRAPH_MPPC_ENCRYPTION
200110409Sambrisko/* Depend on separate rc4 module */
201110409SambriskoMODULE_DEPEND(ng_mppc, rc4, 1, 1, 1);
202110409Sambrisko#endif
203110409Sambrisko
20487971Sarchie/* Fixed bit pattern to weaken keysize down to 40 or 56 bits */
20559109Sarchiestatic const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e };
20659109Sarchie
20759109Sarchie#define ERROUT(x)	do { error = (x); goto done; } while (0)
20859109Sarchie
20959109Sarchie/************************************************************************
21059109Sarchie			NETGRAPH NODE STUFF
21159109Sarchie ************************************************************************/
21259109Sarchie
21359109Sarchie/*
21459109Sarchie * Node type constructor
21559109Sarchie */
21659109Sarchiestatic int
21770700Sjulianng_mppc_constructor(node_p node)
21859109Sarchie{
21959109Sarchie	priv_p priv;
22059109Sarchie
22159109Sarchie	/* Allocate private structure */
222220768Sglebius	priv = malloc(sizeof(*priv), M_NETGRAPH_MPPC, M_WAITOK | M_ZERO);
22359109Sarchie
22470784Sjulian	NG_NODE_SET_PRIVATE(node, priv);
22559109Sarchie
226146919Sglebius	/* This node is not thread safe. */
227146919Sglebius	NG_NODE_FORCE_WRITER(node);
228146919Sglebius
22959109Sarchie	/* Done */
23059109Sarchie	return (0);
23159109Sarchie}
23259109Sarchie
23359109Sarchie/*
23459109Sarchie * Give our OK for a hook to be added
23559109Sarchie */
23659109Sarchiestatic int
23759109Sarchieng_mppc_newhook(node_p node, hook_p hook, const char *name)
23859109Sarchie{
23970784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
24059109Sarchie	hook_p *hookPtr;
24159109Sarchie
24259109Sarchie	/* Check hook name */
24359109Sarchie	if (strcmp(name, NG_MPPC_HOOK_COMP) == 0)
24459109Sarchie		hookPtr = &priv->xmit.hook;
24559109Sarchie	else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0)
24659109Sarchie		hookPtr = &priv->recv.hook;
24759109Sarchie	else
24859109Sarchie		return (EINVAL);
24959109Sarchie
25059109Sarchie	/* See if already connected */
25159109Sarchie	if (*hookPtr != NULL)
25259109Sarchie		return (EISCONN);
25359109Sarchie
25459109Sarchie	/* OK */
25559109Sarchie	*hookPtr = hook;
25659109Sarchie	return (0);
25759109Sarchie}
25859109Sarchie
25959109Sarchie/*
26059109Sarchie * Receive a control message
26159109Sarchie */
26259109Sarchiestatic int
26370700Sjulianng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook)
26459109Sarchie{
26570784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
26659109Sarchie	struct ng_mesg *resp = NULL;
26759109Sarchie	int error = 0;
26870700Sjulian	struct ng_mesg *msg;
26959109Sarchie
27070700Sjulian	NGI_GET_MSG(item, msg);
27159109Sarchie	switch (msg->header.typecookie) {
27259109Sarchie	case NGM_MPPC_COOKIE:
27359109Sarchie		switch (msg->header.cmd) {
27459109Sarchie		case NGM_MPPC_CONFIG_COMP:
27559109Sarchie		case NGM_MPPC_CONFIG_DECOMP:
27659109Sarchie		    {
27759109Sarchie			struct ng_mppc_config *const cfg
27859109Sarchie			    = (struct ng_mppc_config *)msg->data;
27959109Sarchie			const int isComp =
28059109Sarchie			    msg->header.cmd == NGM_MPPC_CONFIG_COMP;
28159109Sarchie			struct ng_mppc_dir *const d = isComp ?
28259109Sarchie			    &priv->xmit : &priv->recv;
28359109Sarchie
28459109Sarchie			/* Check configuration */
28559109Sarchie			if (msg->header.arglen != sizeof(*cfg))
28659109Sarchie				ERROUT(EINVAL);
28759109Sarchie			if (cfg->enable) {
28859109Sarchie				if ((cfg->bits & ~MPPC_VALID_BITS) != 0)
28959109Sarchie					ERROUT(EINVAL);
29059109Sarchie#ifndef NETGRAPH_MPPC_COMPRESSION
29159109Sarchie				if ((cfg->bits & MPPC_BIT) != 0)
29259109Sarchie					ERROUT(EPROTONOSUPPORT);
29359109Sarchie#endif
29459109Sarchie#ifndef NETGRAPH_MPPC_ENCRYPTION
29559109Sarchie				if ((cfg->bits & MPPE_BITS) != 0)
29659109Sarchie					ERROUT(EPROTONOSUPPORT);
29759109Sarchie#endif
29859109Sarchie			} else
29959109Sarchie				cfg->bits = 0;
30059109Sarchie
30159109Sarchie			/* Save return address so we can send reset-req's */
302107845Sarchie			if (!isComp)
303107845Sarchie				priv->ctrlnode = NGI_RETADDR(item);
30459109Sarchie
30559109Sarchie			/* Configuration is OK, reset to it */
30659109Sarchie			d->cfg = *cfg;
30759109Sarchie
30859109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION
30959109Sarchie			/* Initialize state buffers for compression */
31059109Sarchie			if (d->history != NULL) {
311184205Sdes				free(d->history, M_NETGRAPH_MPPC);
31259109Sarchie				d->history = NULL;
31359109Sarchie			}
31459109Sarchie			if ((cfg->bits & MPPC_BIT) != 0) {
315184214Sdes				d->history = malloc(isComp ?
316184214Sdes				    MPPC_SizeOfCompressionHistory() :
31759109Sarchie				    MPPC_SizeOfDecompressionHistory(),
31870870Sjulian				    M_NETGRAPH_MPPC, M_NOWAIT);
31959109Sarchie				if (d->history == NULL)
32059109Sarchie					ERROUT(ENOMEM);
32159109Sarchie				if (isComp)
32259109Sarchie					MPPC_InitCompressionHistory(d->history);
32359109Sarchie				else {
32459109Sarchie					MPPC_InitDecompressionHistory(
32559109Sarchie					    d->history);
32659109Sarchie				}
32759109Sarchie			}
32859109Sarchie#endif
32959109Sarchie
33059109Sarchie#ifdef NETGRAPH_MPPC_ENCRYPTION
33159109Sarchie			/* Generate initial session keys for encryption */
33259109Sarchie			if ((cfg->bits & MPPE_BITS) != 0) {
33359109Sarchie				const int keylen = KEYLEN(cfg->bits);
33459109Sarchie
33559109Sarchie				bcopy(cfg->startkey, d->key, keylen);
33659109Sarchie				ng_mppc_getkey(cfg->startkey, d->key, keylen);
33787971Sarchie				if ((cfg->bits & MPPE_40) != 0)
33887971Sarchie					bcopy(&ng_mppe_weakenkey, d->key, 3);
33987971Sarchie				else if ((cfg->bits & MPPE_56) != 0)
34087971Sarchie					bcopy(&ng_mppe_weakenkey, d->key, 1);
34159109Sarchie				rc4_init(&d->rc4, d->key, keylen);
34259109Sarchie			}
34359109Sarchie#endif
34459109Sarchie
34559109Sarchie			/* Initialize other state */
34659109Sarchie			d->cc = 0;
34759109Sarchie			d->flushed = 0;
34859109Sarchie			break;
34959109Sarchie		    }
35059109Sarchie
35159109Sarchie		case NGM_MPPC_RESETREQ:
35259109Sarchie			ng_mppc_reset_req(node);
35359109Sarchie			break;
35459109Sarchie
35559109Sarchie		default:
35659109Sarchie			error = EINVAL;
35759109Sarchie			break;
35859109Sarchie		}
35959109Sarchie		break;
36059109Sarchie	default:
36159109Sarchie		error = EINVAL;
36259109Sarchie		break;
36359109Sarchie	}
36459109Sarchiedone:
36570700Sjulian	NG_RESPOND_MSG(error, node, item, resp);
36670700Sjulian	NG_FREE_MSG(msg);
36759109Sarchie	return (error);
36859109Sarchie}
36959109Sarchie
37059109Sarchie/*
37159109Sarchie * Receive incoming data on our hook.
37259109Sarchie */
37359109Sarchiestatic int
37470700Sjulianng_mppc_rcvdata(hook_p hook, item_p item)
37559109Sarchie{
37670784Sjulian	const node_p node = NG_HOOK_NODE(hook);
37770784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
37859109Sarchie	int error;
37970700Sjulian	struct mbuf *m;
38059109Sarchie
38170700Sjulian	NGI_GET_M(item, m);
38259109Sarchie	/* Compress and/or encrypt */
38359109Sarchie	if (hook == priv->xmit.hook) {
38459109Sarchie		if (!priv->xmit.cfg.enable) {
38570700Sjulian			NG_FREE_M(m);
38670700Sjulian			NG_FREE_ITEM(item);
38759109Sarchie			return (ENXIO);
38859109Sarchie		}
389169474Smav		if ((error = ng_mppc_compress(node, &m)) != 0) {
39070700Sjulian			NG_FREE_ITEM(item);
39159109Sarchie			return(error);
39259109Sarchie		}
393169474Smav		NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m);
39459109Sarchie		return (error);
39559109Sarchie	}
39659109Sarchie
39759109Sarchie	/* Decompress and/or decrypt */
39859109Sarchie	if (hook == priv->recv.hook) {
39959109Sarchie		if (!priv->recv.cfg.enable) {
40070700Sjulian			NG_FREE_M(m);
40170700Sjulian			NG_FREE_ITEM(item);
40259109Sarchie			return (ENXIO);
40359109Sarchie		}
404169474Smav		if ((error = ng_mppc_decompress(node, &m)) != 0) {
40570700Sjulian			NG_FREE_ITEM(item);
406102244Sarchie			if (error == EINVAL && priv->ctrlnode != 0) {
40759109Sarchie				struct ng_mesg *msg;
40859109Sarchie
40959109Sarchie				/* Need to send a reset-request */
41059109Sarchie				NG_MKMESSAGE(msg, NGM_MPPC_COOKIE,
41159109Sarchie				    NGM_MPPC_RESETREQ, 0, M_NOWAIT);
41259109Sarchie				if (msg == NULL)
41359109Sarchie					return (error);
41470700Sjulian				NG_SEND_MSG_ID(error, node, msg,
415102244Sarchie					priv->ctrlnode, 0);
41659109Sarchie			}
41759109Sarchie			return (error);
41859109Sarchie		}
419169474Smav		NG_FWD_NEW_DATA(error, item, priv->recv.hook, m);
42059109Sarchie		return (error);
42159109Sarchie	}
42259109Sarchie
42359109Sarchie	/* Oops */
42487599Sobrien	panic("%s: unknown hook", __func__);
42559109Sarchie}
42659109Sarchie
42759109Sarchie/*
42859109Sarchie * Destroy node
42959109Sarchie */
43059109Sarchiestatic int
43170700Sjulianng_mppc_shutdown(node_p node)
43259109Sarchie{
43370784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
43459109Sarchie
43559109Sarchie	/* Take down netgraph node */
43659109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION
43759109Sarchie	if (priv->xmit.history != NULL)
438184205Sdes		free(priv->xmit.history, M_NETGRAPH_MPPC);
43959109Sarchie	if (priv->recv.history != NULL)
440184205Sdes		free(priv->recv.history, M_NETGRAPH_MPPC);
44159109Sarchie#endif
44259109Sarchie	bzero(priv, sizeof(*priv));
443184205Sdes	free(priv, M_NETGRAPH_MPPC);
44470784Sjulian	NG_NODE_SET_PRIVATE(node, NULL);
44570784Sjulian	NG_NODE_UNREF(node);		/* let the node escape */
44659109Sarchie	return (0);
44759109Sarchie}
44859109Sarchie
44959109Sarchie/*
45059109Sarchie * Hook disconnection
45159109Sarchie */
45259109Sarchiestatic int
45359109Sarchieng_mppc_disconnect(hook_p hook)
45459109Sarchie{
45570784Sjulian	const node_p node = NG_HOOK_NODE(hook);
45670784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
45759109Sarchie
45859109Sarchie	/* Zero out hook pointer */
45959109Sarchie	if (hook == priv->xmit.hook)
46059109Sarchie		priv->xmit.hook = NULL;
46159109Sarchie	if (hook == priv->recv.hook)
46259109Sarchie		priv->recv.hook = NULL;
46359109Sarchie
46459109Sarchie	/* Go away if no longer connected */
46570784Sjulian	if ((NG_NODE_NUMHOOKS(node) == 0)
46670784Sjulian	&& NG_NODE_IS_VALID(node))
46770700Sjulian		ng_rmnode_self(node);
46859109Sarchie	return (0);
46959109Sarchie}
47059109Sarchie
47159109Sarchie/************************************************************************
47259109Sarchie			HELPER STUFF
47359109Sarchie ************************************************************************/
47459109Sarchie
47559109Sarchie/*
47659109Sarchie * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
47759109Sarchie * The original mbuf is not free'd.
47859109Sarchie */
47959109Sarchiestatic int
480169474Smavng_mppc_compress(node_p node, struct mbuf **datap)
48159109Sarchie{
48270784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
48359109Sarchie	struct ng_mppc_dir *const d = &priv->xmit;
48459109Sarchie	u_int16_t header;
485169474Smav	struct mbuf *m = *datap;
48659109Sarchie
487187405Smav	/* We must own the mbuf chain exclusively to modify it. */
488187405Smav	m = m_unshare(m, M_DONTWAIT);
489187405Smav	if (m == NULL)
490187405Smav		return (ENOMEM);
491187405Smav
49259109Sarchie	/* Initialize */
49359109Sarchie	header = d->cc;
494169262Smav
495169262Smav	/* Always set the flushed bit in stateless mode */
496169262Smav	if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) {
49759109Sarchie		header |= MPPC_FLAG_FLUSHED;
49859109Sarchie		d->flushed = 0;
49959109Sarchie	}
50059109Sarchie
501169474Smav	/* Compress packet (if compression enabled) */
50259109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION
50359109Sarchie	if ((d->cfg.bits & MPPC_BIT) != 0) {
50459109Sarchie		u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS;
505169474Smav		u_char *inbuf, *outbuf;
506187410Smav		int outlen, inlen, ina;
50759109Sarchie		u_char *source, *dest;
50859109Sarchie		u_long sourceCnt, destCnt;
50959109Sarchie		int rtn;
51059109Sarchie
511169474Smav		/* Work with contiguous regions of memory. */
512169474Smav		inlen = m->m_pkthdr.len;
513187410Smav		if (m->m_next == NULL) {
514187410Smav			inbuf = mtod(m, u_char *);
515187410Smav			ina = 0;
516187410Smav		} else {
517187410Smav			inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
518187410Smav			if (inbuf == NULL)
519187410Smav				goto err1;
520187410Smav			m_copydata(m, 0, inlen, (caddr_t)inbuf);
521187410Smav			ina = 1;
522187410Smav		}
523169474Smav
524169474Smav		outlen = MPPC_MAX_BLOWUP(inlen);
525169474Smav		outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT);
526169474Smav		if (outbuf == NULL) {
527187410Smav			if (ina)
528187410Smav				free(inbuf, M_NETGRAPH_MPPC);
529185723Smaverr1:
530169474Smav			m_freem(m);
531185723Smav			MPPC_InitCompressionHistory(d->history);
532185723Smav			d->flushed = 1;
533169474Smav			return (ENOMEM);
534169474Smav		}
535169474Smav
53659109Sarchie		/* Prepare to compress */
53759109Sarchie		source = inbuf;
53859109Sarchie		sourceCnt = inlen;
539169474Smav		dest = outbuf;
540169474Smav		destCnt = outlen;
54159109Sarchie		if ((d->cfg.bits & MPPE_STATELESS) == 0)
54259109Sarchie			flags |= MPPC_SAVE_HISTORY;
54359109Sarchie
54459109Sarchie		/* Compress */
54559109Sarchie		rtn = MPPC_Compress(&source, &dest, &sourceCnt,
54659109Sarchie			&destCnt, d->history, flags, 0);
54759109Sarchie
54859109Sarchie		/* Check return value */
54987599Sobrien		KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
55059109Sarchie		if ((rtn & MPPC_EXPANDED) == 0
55159109Sarchie		    && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) {
55259109Sarchie			outlen -= destCnt;
55359109Sarchie			header |= MPPC_FLAG_COMPRESSED;
55459109Sarchie			if ((rtn & MPPC_RESTART_HISTORY) != 0)
55559109Sarchie				header |= MPPC_FLAG_RESTART;
556169474Smav
557169474Smav			/* Replace m by the compresed one. */
558187405Smav			m_copyback(m, 0, outlen, (caddr_t)outbuf);
559187405Smav			if (m->m_pkthdr.len < outlen) {
560187405Smav				m_freem(m);
561187405Smav				m = NULL;
562187405Smav			} else if (outlen < m->m_pkthdr.len)
563187405Smav				m_adj(m, outlen - m->m_pkthdr.len);
56459109Sarchie		}
56559109Sarchie		d->flushed = (rtn & MPPC_EXPANDED) != 0
56659109Sarchie		    || (flags & MPPC_SAVE_HISTORY) == 0;
567169474Smav
568187410Smav		if (ina)
569187410Smav			free(inbuf, M_NETGRAPH_MPPC);
570169474Smav		free(outbuf, M_NETGRAPH_MPPC);
571169474Smav
572187405Smav		/* Check mbuf chain reload result. */
573185723Smav		if (m == NULL) {
574185723Smav			if (!d->flushed) {
575185723Smav				MPPC_InitCompressionHistory(d->history);
576185723Smav				d->flushed = 1;
577185723Smav			}
578169474Smav			return (ENOMEM);
579185723Smav		}
58059109Sarchie	}
58159109Sarchie#endif
58259109Sarchie
58359109Sarchie	/* Now encrypt packet (if encryption enabled) */
58459109Sarchie#ifdef NETGRAPH_MPPC_ENCRYPTION
58559109Sarchie	if ((d->cfg.bits & MPPE_BITS) != 0) {
586169474Smav		struct mbuf *m1;
58759109Sarchie
588169263Smav		/* Set header bits */
58959109Sarchie		header |= MPPC_FLAG_ENCRYPTED;
59059109Sarchie
59159109Sarchie		/* Update key if it's time */
59259109Sarchie		if ((d->cfg.bits & MPPE_STATELESS) != 0
59359109Sarchie		    || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
594169263Smav			ng_mppc_updatekey(d->cfg.bits,
595169263Smav			    d->cfg.startkey, d->key, &d->rc4);
596169263Smav		} else if ((header & MPPC_FLAG_FLUSHED) != 0) {
597169263Smav			/* Need to reset key if we say we did
598169263Smav			   and ng_mppc_updatekey wasn't called to do it also. */
599169263Smav			rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
60059109Sarchie		}
60159109Sarchie
60259109Sarchie		/* Encrypt packet */
603169474Smav		m1 = m;
604169474Smav		while (m1) {
605169474Smav			rc4_crypt(&d->rc4, mtod(m1, u_char *),
606169474Smav			    mtod(m1, u_char *), m1->m_len);
607169474Smav			m1 = m1->m_next;
608169474Smav		}
60959109Sarchie	}
61059109Sarchie#endif
61159109Sarchie
612169261Smav	/* Update coherency count for next time (12 bit arithmetic) */
613169261Smav	MPPC_CCOUNT_INC(d->cc);
61459109Sarchie
61559109Sarchie	/* Install header */
616169474Smav	M_PREPEND(m, MPPC_HDRLEN, M_DONTWAIT);
617169474Smav	if (m != NULL)
618206021Smav		be16enc(mtod(m, void *), header);
61959109Sarchie
620169474Smav	*datap = m;
621169474Smav	return (*datap == NULL ? ENOBUFS : 0);
62259109Sarchie}
62359109Sarchie
62459109Sarchie/*
62559109Sarchie * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
62659109Sarchie * The original mbuf is not free'd.
62759109Sarchie */
62859109Sarchiestatic int
629169474Smavng_mppc_decompress(node_p node, struct mbuf **datap)
63059109Sarchie{
63170784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
63259109Sarchie	struct ng_mppc_dir *const d = &priv->recv;
633107845Sarchie	u_int16_t header, cc;
634107845Sarchie	u_int numLost;
635169474Smav	struct mbuf *m = *datap;
63659109Sarchie
637187405Smav	/* We must own the mbuf chain exclusively to modify it. */
638187405Smav	m = m_unshare(m, M_DONTWAIT);
639187405Smav	if (m == NULL)
640187405Smav		return (ENOMEM);
641187405Smav
64259109Sarchie	/* Pull off header */
643169474Smav	if (m->m_pkthdr.len < MPPC_HDRLEN) {
644169474Smav		m_freem(m);
64559109Sarchie		return (EINVAL);
646169474Smav	}
647206021Smav	header = be16dec(mtod(m, void *));
64859109Sarchie	cc = (header & MPPC_CCOUNT_MASK);
649169474Smav	m_adj(m, MPPC_HDRLEN);
65059109Sarchie
651107845Sarchie	/* Check for an unexpected jump in the sequence number */
65259109Sarchie	numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK);
65359109Sarchie
65459109Sarchie	/* If flushed bit set, we can always handle packet */
65559109Sarchie	if ((header & MPPC_FLAG_FLUSHED) != 0) {
65659109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION
65759109Sarchie		if (d->history != NULL)
65859109Sarchie			MPPC_InitDecompressionHistory(d->history);
65959109Sarchie#endif
66059109Sarchie#ifdef NETGRAPH_MPPC_ENCRYPTION
66159109Sarchie		if ((d->cfg.bits & MPPE_BITS) != 0) {
662107845Sarchie			u_int rekey;
66359109Sarchie
664107845Sarchie			/* How many times are we going to have to re-key? */
665107845Sarchie			rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ?
666107845Sarchie			    numLost : (numLost / (MPPE_UPDATE_MASK + 1));
667267094Smav			if (rekey > mppe_max_rekey) {
668267094Smav			    if (mppe_block_on_max_rekey) {
669267094Smav				if (mppe_log_max_rekey) {
670267094Smav				    log(LOG_ERR, "%s: too many (%d) packets"
671267094Smav					" dropped, disabling node %p!\n",
672267094Smav					__func__, numLost, node);
673267094Smav				}
674107845Sarchie				priv->recv.cfg.enable = 0;
675107845Sarchie				goto failed;
676267094Smav			    } else {
677267094Smav				if (mppe_log_max_rekey) {
678267094Smav				    log(LOG_ERR, "%s: %d packets"
679267094Smav					" dropped, node %p\n",
680267094Smav					__func__, numLost, node);
681267094Smav				}
682267094Smav				goto failed;
683267094Smav			    }
684107845Sarchie			}
685107845Sarchie
686107845Sarchie			/* Re-key as necessary to catch up to peer */
68759109Sarchie			while (d->cc != cc) {
688107845Sarchie				if ((d->cfg.bits & MPPE_STATELESS) != 0
68959109Sarchie				    || (d->cc & MPPE_UPDATE_MASK)
69059109Sarchie				      == MPPE_UPDATE_FLAG) {
69159109Sarchie					ng_mppc_updatekey(d->cfg.bits,
69259109Sarchie					    d->cfg.startkey, d->key, &d->rc4);
69359109Sarchie				}
694169261Smav				MPPC_CCOUNT_INC(d->cc);
69559109Sarchie			}
69659109Sarchie
69759109Sarchie			/* Reset key (except in stateless mode, see below) */
69859109Sarchie			if ((d->cfg.bits & MPPE_STATELESS) == 0)
69959109Sarchie				rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
70059109Sarchie		}
70159109Sarchie#endif
70259109Sarchie		d->cc = cc;		/* skip over lost seq numbers */
70359109Sarchie		numLost = 0;		/* act like no packets were lost */
70459109Sarchie	}
70559109Sarchie
70659109Sarchie	/* Can't decode non-sequential packets without a flushed bit */
70759109Sarchie	if (numLost != 0)
70859109Sarchie		goto failed;
70959109Sarchie
71059109Sarchie	/* Decrypt packet */
71159109Sarchie	if ((header & MPPC_FLAG_ENCRYPTED) != 0) {
712169474Smav#ifdef NETGRAPH_MPPC_ENCRYPTION
713169474Smav		struct mbuf *m1;
714169474Smav#endif
71559109Sarchie
71659109Sarchie		/* Are we not expecting encryption? */
71759109Sarchie		if ((d->cfg.bits & MPPE_BITS) == 0) {
71859109Sarchie			log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
71987599Sobrien				__func__, "encrypted");
72059109Sarchie			goto failed;
72159109Sarchie		}
72259109Sarchie
72359109Sarchie#ifdef NETGRAPH_MPPC_ENCRYPTION
72459109Sarchie		/* Update key if it's time (always in stateless mode) */
72559109Sarchie		if ((d->cfg.bits & MPPE_STATELESS) != 0
72659109Sarchie		    || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
72759109Sarchie			ng_mppc_updatekey(d->cfg.bits,
72859109Sarchie			    d->cfg.startkey, d->key, &d->rc4);
72959109Sarchie		}
73059109Sarchie
73159109Sarchie		/* Decrypt packet */
732169474Smav		m1 = m;
733169474Smav		while (m1 != NULL) {
734169474Smav			rc4_crypt(&d->rc4, mtod(m1, u_char *),
735169474Smav			    mtod(m1, u_char *), m1->m_len);
736169474Smav			m1 = m1->m_next;
737169474Smav		}
73859109Sarchie#endif
73959109Sarchie	} else {
74059109Sarchie
74159109Sarchie		/* Are we expecting encryption? */
74259109Sarchie		if ((d->cfg.bits & MPPE_BITS) != 0) {
74359109Sarchie			log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
74487599Sobrien				__func__, "unencrypted");
74559109Sarchie			goto failed;
74659109Sarchie		}
74759109Sarchie	}
74859109Sarchie
74959109Sarchie	/* Update coherency count for next time (12 bit arithmetic) */
750169261Smav	MPPC_CCOUNT_INC(d->cc);
75159109Sarchie
75259109Sarchie	/* Check for unexpected compressed packet */
75359109Sarchie	if ((header & MPPC_FLAG_COMPRESSED) != 0
75459109Sarchie	    && (d->cfg.bits & MPPC_BIT) == 0) {
75559109Sarchie		log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
75687599Sobrien			__func__, "compressed");
75759109Sarchiefailed:
758169474Smav		m_freem(m);
75959109Sarchie		return (EINVAL);
76059109Sarchie	}
76159109Sarchie
76259109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION
76359109Sarchie	/* Decompress packet */
76459109Sarchie	if ((header & MPPC_FLAG_COMPRESSED) != 0) {
76559109Sarchie		int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS;
766187410Smav		u_char *inbuf, *outbuf;
767187410Smav		int inlen, outlen, ina;
768187410Smav		u_char *source, *dest;
76959109Sarchie		u_long sourceCnt, destCnt;
770187410Smav		int rtn;
77159109Sarchie
772169474Smav		/* Copy payload into a contiguous region of memory. */
773187410Smav		inlen = m->m_pkthdr.len;
774187410Smav		if (m->m_next == NULL) {
775187410Smav                	inbuf = mtod(m, u_char *);
776187410Smav			ina = 0;
777187410Smav		} else {
778187410Smav		        inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
779187410Smav			if (inbuf == NULL) {
780187410Smav				m_freem(m);
781187410Smav				return (ENOMEM);
782187410Smav			}
783187410Smav			m_copydata(m, 0, inlen, (caddr_t)inbuf);
784187410Smav			ina = 1;
785169474Smav		}
786169474Smav
78759109Sarchie		/* Allocate a buffer for decompressed data */
788187410Smav		outbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY,
789169474Smav		    M_NETGRAPH_MPPC, M_NOWAIT);
790187410Smav		if (outbuf == NULL) {
791169474Smav			m_freem(m);
792187410Smav			if (ina)
793187410Smav				free(inbuf, M_NETGRAPH_MPPC);
79459109Sarchie			return (ENOMEM);
79559109Sarchie		}
796187410Smav		outlen = MPPC_DECOMP_BUFSIZE;
79759109Sarchie
79859109Sarchie		/* Prepare to decompress */
799187410Smav		source = inbuf;
800187410Smav		sourceCnt = inlen;
801187410Smav		dest = outbuf;
802187410Smav		destCnt = outlen;
80359109Sarchie		if ((header & MPPC_FLAG_RESTART) != 0)
80459109Sarchie			flags |= MPPC_RESTART_HISTORY;
80559109Sarchie
80659109Sarchie		/* Decompress */
80759109Sarchie		rtn = MPPC_Decompress(&source, &dest,
80859109Sarchie			&sourceCnt, &destCnt, d->history, flags);
80959109Sarchie
81059109Sarchie		/* Check return value */
81187599Sobrien		KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
81259109Sarchie		if ((rtn & MPPC_DEST_EXHAUSTED) != 0
81359109Sarchie		    || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) {
81459109Sarchie			log(LOG_ERR, "%s: decomp returned 0x%x",
81587599Sobrien			    __func__, rtn);
816187410Smav			if (ina)
817187410Smav				free(inbuf, M_NETGRAPH_MPPC);
818187410Smav			free(outbuf, M_NETGRAPH_MPPC);
81959109Sarchie			goto failed;
82059109Sarchie		}
82159109Sarchie
82259109Sarchie		/* Replace compressed data with decompressed data */
823187410Smav		if (ina)
824187410Smav			free(inbuf, M_NETGRAPH_MPPC);
825187410Smav		outlen -= destCnt;
826169474Smav
827187410Smav		m_copyback(m, 0, outlen, (caddr_t)outbuf);
828187410Smav		if (m->m_pkthdr.len < outlen) {
829187405Smav			m_freem(m);
830187405Smav			m = NULL;
831187410Smav		} else if (outlen < m->m_pkthdr.len)
832187410Smav			m_adj(m, outlen - m->m_pkthdr.len);
833187410Smav		free(outbuf, M_NETGRAPH_MPPC);
83459109Sarchie	}
83559109Sarchie#endif
83659109Sarchie
83759109Sarchie	/* Return result in an mbuf */
838169474Smav	*datap = m;
839169474Smav	return (*datap == NULL ? ENOBUFS : 0);
84059109Sarchie}
84159109Sarchie
84259109Sarchie/*
84359109Sarchie * The peer has sent us a CCP ResetRequest, so reset our transmit state.
84459109Sarchie */
84559109Sarchiestatic void
84659109Sarchieng_mppc_reset_req(node_p node)
84759109Sarchie{
84870784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
84959109Sarchie	struct ng_mppc_dir *const d = &priv->xmit;
85059109Sarchie
85159109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION
85259109Sarchie	if (d->history != NULL)
85359109Sarchie		MPPC_InitCompressionHistory(d->history);
85459109Sarchie#endif
85559109Sarchie#ifdef NETGRAPH_MPPC_ENCRYPTION
85659109Sarchie	if ((d->cfg.bits & MPPE_STATELESS) == 0)
85759109Sarchie		rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
85859109Sarchie#endif
85959109Sarchie	d->flushed = 1;
86059109Sarchie}
86159109Sarchie
862169678Smav#ifdef NETGRAPH_MPPC_ENCRYPTION
86359109Sarchie/*
86459109Sarchie * Generate a new encryption key
86559109Sarchie */
86659109Sarchiestatic void
86759109Sarchieng_mppc_getkey(const u_char *h, u_char *h2, int len)
86859109Sarchie{
869186189Smav	static const u_char pad1[40] =
870186189Smav	    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
871186189Smav	      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
872186189Smav	      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
873186189Smav	      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
874186189Smav	static const u_char pad2[40] =
875186189Smav	    { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
876186189Smav	      0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
877186189Smav	      0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
878186189Smav	      0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2 };
87959109Sarchie	u_char hash[20];
88059109Sarchie	SHA1_CTX c;
88159109Sarchie
88259109Sarchie	SHA1Init(&c);
88359109Sarchie	SHA1Update(&c, h, len);
884186189Smav	SHA1Update(&c, pad1, sizeof(pad1));
88559109Sarchie	SHA1Update(&c, h2, len);
886186189Smav	SHA1Update(&c, pad2, sizeof(pad2));
88759109Sarchie	SHA1Final(hash, &c);
88859109Sarchie	bcopy(hash, h2, len);
88959109Sarchie}
89059109Sarchie
89159109Sarchie/*
89259109Sarchie * Update the encryption key
89359109Sarchie */
89459109Sarchiestatic void
89559109Sarchieng_mppc_updatekey(u_int32_t bits,
89659109Sarchie	u_char *key0, u_char *key, struct rc4_state *rc4)
89759109Sarchie{
89859109Sarchie	const int keylen = KEYLEN(bits);
89959109Sarchie
90059109Sarchie	ng_mppc_getkey(key0, key, keylen);
90159109Sarchie	rc4_init(rc4, key, keylen);
90259109Sarchie	rc4_crypt(rc4, key, key, keylen);
90387971Sarchie	if ((bits & MPPE_40) != 0)
90487971Sarchie		bcopy(&ng_mppe_weakenkey, key, 3);
90587971Sarchie	else if ((bits & MPPE_56) != 0)
90687971Sarchie		bcopy(&ng_mppe_weakenkey, key, 1);
90759109Sarchie	rc4_init(rc4, key, keylen);
90859109Sarchie}
909169678Smav#endif
91059109Sarchie
911