Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b3f9b92a authored by Matt Domsch's avatar Matt Domsch Committed by David S. Miller
Browse files

[PPP]: add PPP MPPE encryption module



From: Matt Domsch <Matt_Domsch@dell.com>

The patch below implements the Microsoft Point-to-Point Encryption method
as a PPP compressor/decompressor.  This is necessary for Linux clients and
servers to interoperate with Microsoft Point-to-Point Tunneling Protocol
(PPTP) servers (either Microsoft PPTP servers or the poptop project) which
use MPPE to encrypt data when creating a VPN.

This patch differs from the kernel_ppp_mppe DKMS pacakge at
pptpclient.sourceforge.net by utilizing the kernel crypto routines rather
than providing its own SHA1 and arcfour implementations.

Minor changes to ppp_generic.c try to prevent a link from disabling
compression (in our case, the encryption) after it has started using
compression (encryption).

Feedback to <pptpclient-devel@lists.sourceforge.net> please.

Signed-off-by: default avatarMatt Domsch <Matt_Domsch@dell.com>
Cc: James Cameron <james.cameron@hp.com>
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: default avatarBrice Goglin <Brice.Goglin@ens-lyon.org>
Acked-by: default avatarPaul Mackerras <paulus@samba.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6722e78c
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -2523,6 +2523,19 @@ config PPP_BSDCOMP
	  module; it is called bsd_comp and will show up in the directory
	  modules once you have said "make modules". If unsure, say N.

config PPP_MPPE
       tristate "PPP MPPE compression (encryption) (EXPERIMENTAL)"
       depends on PPP && EXPERIMENTAL
       select CRYPTO
       select CRYPTO_SHA1
       select CRYPTO_ARC4
       ---help---
         Support for the MPPE Encryption protocol, as employed by the
	 Microsoft Point-to-Point Tunneling Protocol.

	 See http://pptpclient.sourceforge.net/ for information on
	 configuring PPTP clients and servers to utilize this method.

config PPPOE
	tristate "PPP over Ethernet (EXPERIMENTAL)"
	depends on EXPERIMENTAL && PPP
+1 −0
Original line number Diff line number Diff line
@@ -112,6 +112,7 @@ obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o
obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o
obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o
obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o
obj-$(CONFIG_PPPOE) += pppox.o pppoe.o

obj-$(CONFIG_SLIP) += slip.o
+64 −24
Original line number Diff line number Diff line
@@ -137,13 +137,14 @@ struct ppp {

/*
 * Bits in flags: SC_NO_TCP_CCID, SC_CCP_OPEN, SC_CCP_UP, SC_LOOP_TRAFFIC,
 * SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ, SC_COMP_TCP, SC_REJ_COMP_TCP.
 * SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ, SC_COMP_TCP, SC_REJ_COMP_TCP,
 * SC_MUST_COMP
 * Bits in rstate: SC_DECOMP_RUN, SC_DC_ERROR, SC_DC_FERROR.
 * Bits in xstate: SC_COMP_RUN
 */
#define SC_FLAG_BITS	(SC_NO_TCP_CCID|SC_CCP_OPEN|SC_CCP_UP|SC_LOOP_TRAFFIC \
			 |SC_MULTILINK|SC_MP_SHORTSEQ|SC_MP_XSHORTSEQ \
			 |SC_COMP_TCP|SC_REJ_COMP_TCP)
			 |SC_COMP_TCP|SC_REJ_COMP_TCP|SC_MUST_COMP)

/*
 * Private data structure for each channel.
@@ -1027,6 +1028,56 @@ ppp_xmit_process(struct ppp *ppp)
	ppp_xmit_unlock(ppp);
}

static inline struct sk_buff *
pad_compress_skb(struct ppp *ppp, struct sk_buff *skb)
{
	struct sk_buff *new_skb;
	int len;
	int new_skb_size = ppp->dev->mtu +
		ppp->xcomp->comp_extra + ppp->dev->hard_header_len;
	int compressor_skb_size = ppp->dev->mtu +
		ppp->xcomp->comp_extra + PPP_HDRLEN;
	new_skb = alloc_skb(new_skb_size, GFP_ATOMIC);
	if (!new_skb) {
		if (net_ratelimit())
			printk(KERN_ERR "PPP: no memory (comp pkt)\n");
		return NULL;
	}
	if (ppp->dev->hard_header_len > PPP_HDRLEN)
		skb_reserve(new_skb,
			    ppp->dev->hard_header_len - PPP_HDRLEN);

	/* compressor still expects A/C bytes in hdr */
	len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2,
				   new_skb->data, skb->len + 2,
				   compressor_skb_size);
	if (len > 0 && (ppp->flags & SC_CCP_UP)) {
		kfree_skb(skb);
		skb = new_skb;
		skb_put(skb, len);
		skb_pull(skb, 2);	/* pull off A/C bytes */
	} else if (len == 0) {
		/* didn't compress, or CCP not up yet */
		kfree_skb(new_skb);
		new_skb = skb;
	} else {
		/*
		 * (len < 0)
		 * MPPE requires that we do not send unencrypted
		 * frames.  The compressor will return -1 if we
		 * should drop the frame.  We cannot simply test
		 * the compress_proto because MPPE and MPPC share
		 * the same number.
		 */
		if (net_ratelimit())
			printk(KERN_ERR "ppp: compressor dropped pkt\n");
		kfree_skb(skb);
		kfree_skb(new_skb);
		new_skb = NULL;
	}
	return new_skb;
}

/*
 * Compress and send a frame.
 * The caller should have locked the xmit path,
@@ -1113,29 +1164,14 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
	/* try to do packet compression */
	if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0
	    && proto != PPP_LCP && proto != PPP_CCP) {
		new_skb = alloc_skb(ppp->dev->mtu + ppp->dev->hard_header_len,
				    GFP_ATOMIC);
		if (new_skb == 0) {
			printk(KERN_ERR "PPP: no memory (comp pkt)\n");
		if (!(ppp->flags & SC_CCP_UP) && (ppp->flags & SC_MUST_COMP)) {
			if (net_ratelimit())
				printk(KERN_ERR "ppp: compression required but down - pkt dropped.\n");
			goto drop;
		}
		if (ppp->dev->hard_header_len > PPP_HDRLEN)
			skb_reserve(new_skb,
				    ppp->dev->hard_header_len - PPP_HDRLEN);

		/* compressor still expects A/C bytes in hdr */
		len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2,
					   new_skb->data, skb->len + 2,
					   ppp->dev->mtu + PPP_HDRLEN);
		if (len > 0 && (ppp->flags & SC_CCP_UP)) {
			kfree_skb(skb);
			skb = new_skb;
			skb_put(skb, len);
			skb_pull(skb, 2);	/* pull off A/C bytes */
		} else {
			/* didn't compress, or CCP not up yet */
			kfree_skb(new_skb);
		}
		skb = pad_compress_skb(ppp, skb);
		if (!skb)
			goto drop;
	}

	/*
@@ -1155,6 +1191,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
	return;

 drop:
	if (skb)
		kfree_skb(skb);
	++ppp->stats.tx_errors;
}
@@ -1552,6 +1589,9 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
	    && (ppp->rstate & (SC_DC_FERROR | SC_DC_ERROR)) == 0)
		skb = ppp_decompress_frame(ppp, skb);

	if (ppp->flags & SC_MUST_COMP && ppp->rstate & SC_DC_FERROR)
		goto err;

	proto = PPP_PROTO(skb);
	switch (proto) {
	case PPP_VJC_COMP:

drivers/net/ppp_mppe.c

0 → 100644
+724 −0

File added.

Preview size limit exceeded, changes collapsed.

drivers/net/ppp_mppe.h

0 → 100644
+86 −0
Original line number Diff line number Diff line
#define MPPE_PAD                4      /* MPPE growth per frame */
#define MPPE_MAX_KEY_LEN       16      /* largest key length (128-bit) */

/* option bits for ccp_options.mppe */
#define MPPE_OPT_40            0x01    /* 40 bit */
#define MPPE_OPT_128           0x02    /* 128 bit */
#define MPPE_OPT_STATEFUL      0x04    /* stateful mode */
/* unsupported opts */
#define MPPE_OPT_56            0x08    /* 56 bit */
#define MPPE_OPT_MPPC          0x10    /* MPPC compression */
#define MPPE_OPT_D             0x20    /* Unknown */
#define MPPE_OPT_UNSUPPORTED (MPPE_OPT_56|MPPE_OPT_MPPC|MPPE_OPT_D)
#define MPPE_OPT_UNKNOWN       0x40    /* Bits !defined in RFC 3078 were set */

/*
 * This is not nice ... the alternative is a bitfield struct though.
 * And unfortunately, we cannot share the same bits for the option
 * names above since C and H are the same bit.  We could do a u_int32
 * but then we have to do a htonl() all the time and/or we still need
 * to know which octet is which.
 */
#define MPPE_C_BIT             0x01    /* MPPC */
#define MPPE_D_BIT             0x10    /* Obsolete, usage unknown */
#define MPPE_L_BIT             0x20    /* 40-bit */
#define MPPE_S_BIT             0x40    /* 128-bit */
#define MPPE_M_BIT             0x80    /* 56-bit, not supported */
#define MPPE_H_BIT             0x01    /* Stateless (in a different byte) */

/* Does not include H bit; used for least significant octet only. */
#define MPPE_ALL_BITS (MPPE_D_BIT|MPPE_L_BIT|MPPE_S_BIT|MPPE_M_BIT|MPPE_H_BIT)

/* Build a CI from mppe opts (see RFC 3078) */
#define MPPE_OPTS_TO_CI(opts, ci)              \
    do {                                       \
       u_char *ptr = ci; /* u_char[4] */       \
                                               \
       /* H bit */                             \
       if (opts & MPPE_OPT_STATEFUL)           \
           *ptr++ = 0x0;                       \
       else                                    \
           *ptr++ = MPPE_H_BIT;                \
       *ptr++ = 0;                             \
       *ptr++ = 0;                             \
                                               \
       /* S,L bits */                          \
       *ptr = 0;                               \
       if (opts & MPPE_OPT_128)                \
           *ptr |= MPPE_S_BIT;                 \
       if (opts & MPPE_OPT_40)                 \
           *ptr |= MPPE_L_BIT;                 \
       /* M,D,C bits not supported */          \
    } while (/* CONSTCOND */ 0)

/* The reverse of the above */
#define MPPE_CI_TO_OPTS(ci, opts)              \
    do {                                       \
       u_char *ptr = ci; /* u_char[4] */       \
                                               \
       opts = 0;                               \
                                               \
       /* H bit */                             \
       if (!(ptr[0] & MPPE_H_BIT))             \
           opts |= MPPE_OPT_STATEFUL;          \
                                               \
       /* S,L bits */                          \
       if (ptr[3] & MPPE_S_BIT)                \
           opts |= MPPE_OPT_128;               \
       if (ptr[3] & MPPE_L_BIT)                \
           opts |= MPPE_OPT_40;                \
                                               \
       /* M,D,C bits */                        \
       if (ptr[3] & MPPE_M_BIT)                \
           opts |= MPPE_OPT_56;                \
       if (ptr[3] & MPPE_D_BIT)                \
           opts |= MPPE_OPT_D;                 \
       if (ptr[3] & MPPE_C_BIT)                \
           opts |= MPPE_OPT_MPPC;              \
                                               \
       /* Other bits */                        \
       if (ptr[0] & ~MPPE_H_BIT)               \
           opts |= MPPE_OPT_UNKNOWN;           \
       if (ptr[1] || ptr[2])                   \
           opts |= MPPE_OPT_UNKNOWN;           \
       if (ptr[3] & ~MPPE_ALL_BITS)            \
           opts |= MPPE_OPT_UNKNOWN;           \
    } while (/* CONSTCOND */ 0)
Loading