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
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
......
......@@ -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
......
......@@ -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:
......
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 @@
*/
/*
* ==FILEVERSION 20000724==
* ==FILEVERSION 20050812==
*
* NOTE TO MAINTAINERS:
* If you modify this file at all, please set the above date.
......@@ -35,6 +35,8 @@
#ifndef _IF_PPP_H_
#define _IF_PPP_H_
#include <linux/compiler.h>
/*
* Packet sizes
*/
......@@ -70,7 +72,8 @@
#define SC_LOG_RAWIN 0x00080000 /* log all chars received */
#define SC_LOG_FLUSH 0x00100000 /* log all chars flushed */
#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 */
#define SC_XMIT_BUSY 0x10000000 /* (used by isdn_ppp?) */
......
......@@ -111,6 +111,8 @@ struct compressor {
/* Used in locking compressor modules */
struct module *owner;
/* Extra skb space needed by the compressor algorithm */
unsigned int comp_extra;
};
/*
......@@ -190,6 +192,13 @@ struct compressor {
#define DEFLATE_MAKE_OPT(w) ((((w) - 8) << 4) + DEFLATE_METHOD_VAL)
#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.
*/
......
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