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

[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
...@@ -2523,6 +2523,19 @@ config PPP_BSDCOMP ...@@ -2523,6 +2523,19 @@ config PPP_BSDCOMP
module; it is called bsd_comp and will show up in the directory module; it is called bsd_comp and will show up in the directory
modules once you have said "make modules". If unsure, say N. 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 config PPPOE
tristate "PPP over Ethernet (EXPERIMENTAL)" tristate "PPP over Ethernet (EXPERIMENTAL)"
depends on EXPERIMENTAL && PPP depends on EXPERIMENTAL && PPP
......
...@@ -112,6 +112,7 @@ obj-$(CONFIG_PPP_ASYNC) += ppp_async.o ...@@ -112,6 +112,7 @@ obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o
obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o
obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o
obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o
obj-$(CONFIG_PPPOE) += pppox.o pppoe.o obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
obj-$(CONFIG_SLIP) += slip.o obj-$(CONFIG_SLIP) += slip.o
......
...@@ -137,13 +137,14 @@ struct ppp { ...@@ -137,13 +137,14 @@ struct ppp {
/* /*
* Bits in flags: SC_NO_TCP_CCID, SC_CCP_OPEN, SC_CCP_UP, SC_LOOP_TRAFFIC, * 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 rstate: SC_DECOMP_RUN, SC_DC_ERROR, SC_DC_FERROR.
* Bits in xstate: SC_COMP_RUN * Bits in xstate: SC_COMP_RUN
*/ */
#define SC_FLAG_BITS (SC_NO_TCP_CCID|SC_CCP_OPEN|SC_CCP_UP|SC_LOOP_TRAFFIC \ #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_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. * Private data structure for each channel.
...@@ -1027,6 +1028,56 @@ ppp_xmit_process(struct ppp *ppp) ...@@ -1027,6 +1028,56 @@ ppp_xmit_process(struct ppp *ppp)
ppp_xmit_unlock(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. * Compress and send a frame.
* The caller should have locked the xmit path, * The caller should have locked the xmit path,
...@@ -1113,29 +1164,14 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) ...@@ -1113,29 +1164,14 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
/* try to do packet compression */ /* try to do packet compression */
if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0 if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0
&& proto != PPP_LCP && proto != PPP_CCP) { && proto != PPP_LCP && proto != PPP_CCP) {
new_skb = alloc_skb(ppp->dev->mtu + ppp->dev->hard_header_len, if (!(ppp->flags & SC_CCP_UP) && (ppp->flags & SC_MUST_COMP)) {
GFP_ATOMIC); if (net_ratelimit())
if (new_skb == 0) { printk(KERN_ERR "ppp: compression required but down - pkt dropped.\n");
printk(KERN_ERR "PPP: no memory (comp pkt)\n");
goto drop; goto drop;
} }
if (ppp->dev->hard_header_len > PPP_HDRLEN) skb = pad_compress_skb(ppp, skb);
skb_reserve(new_skb, if (!skb)
ppp->dev->hard_header_len - PPP_HDRLEN); goto drop;
/* 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);
}
} }
/* /*
...@@ -1155,7 +1191,8 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) ...@@ -1155,7 +1191,8 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
return; return;
drop: drop:
kfree_skb(skb); if (skb)
kfree_skb(skb);
++ppp->stats.tx_errors; ++ppp->stats.tx_errors;
} }
...@@ -1552,6 +1589,9 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) ...@@ -1552,6 +1589,9 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
&& (ppp->rstate & (SC_DC_FERROR | SC_DC_ERROR)) == 0) && (ppp->rstate & (SC_DC_FERROR | SC_DC_ERROR)) == 0)
skb = ppp_decompress_frame(ppp, skb); skb = ppp_decompress_frame(ppp, skb);
if (ppp->flags & SC_MUST_COMP && ppp->rstate & SC_DC_FERROR)
goto err;
proto = PPP_PROTO(skb); proto = PPP_PROTO(skb);
switch (proto) { switch (proto) {
case PPP_VJC_COMP: case PPP_VJC_COMP:
......
This diff is collapsed.
#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)
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
*/ */
/* /*
* ==FILEVERSION 20000724== * ==FILEVERSION 20050812==
* *
* NOTE TO MAINTAINERS: * NOTE TO MAINTAINERS:
* If you modify this file at all, please set the above date. * If you modify this file at all, please set the above date.
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
#ifndef _IF_PPP_H_ #ifndef _IF_PPP_H_
#define _IF_PPP_H_ #define _IF_PPP_H_
#include <linux/compiler.h>
/* /*
* Packet sizes * Packet sizes
*/ */
...@@ -70,7 +72,8 @@ ...@@ -70,7 +72,8 @@
#define SC_LOG_RAWIN 0x00080000 /* log all chars received */ #define SC_LOG_RAWIN 0x00080000 /* log all chars received */
#define SC_LOG_FLUSH 0x00100000 /* log all chars flushed */ #define SC_LOG_FLUSH 0x00100000 /* log all chars flushed */
#define SC_SYNC 0x00200000 /* synchronous serial mode */ #define SC_SYNC 0x00200000 /* synchronous serial mode */
#define SC_MASK 0x0f200fff /* bits that user can change */ #define SC_MUST_COMP 0x00400000 /* no uncompressed packets may be sent or received */
#define SC_MASK 0x0f600fff /* bits that user can change */
/* state bits */ /* state bits */
#define SC_XMIT_BUSY 0x10000000 /* (used by isdn_ppp?) */ #define SC_XMIT_BUSY 0x10000000 /* (used by isdn_ppp?) */
......
...@@ -111,6 +111,8 @@ struct compressor { ...@@ -111,6 +111,8 @@ struct compressor {
/* Used in locking compressor modules */ /* Used in locking compressor modules */
struct module *owner; struct module *owner;
/* Extra skb space needed by the compressor algorithm */
unsigned int comp_extra;
}; };
/* /*
...@@ -190,6 +192,13 @@ struct compressor { ...@@ -190,6 +192,13 @@ struct compressor {
#define DEFLATE_MAKE_OPT(w) ((((w) - 8) << 4) + DEFLATE_METHOD_VAL) #define DEFLATE_MAKE_OPT(w) ((((w) - 8) << 4) + DEFLATE_METHOD_VAL)
#define DEFLATE_CHK_SEQUENCE 0 #define DEFLATE_CHK_SEQUENCE 0
/*
* Definitions for MPPE.
*/
#define CI_MPPE 18 /* config option for MPPE */
#define CILEN_MPPE 6 /* length of config option */
/* /*
* Definitions for other, as yet unsupported, compression methods. * Definitions for other, as yet unsupported, compression methods.
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment