diff options
Diffstat (limited to 'src/mppe.c')
-rw-r--r-- | src/mppe.c | 817 |
1 files changed, 817 insertions, 0 deletions
diff --git a/src/mppe.c b/src/mppe.c new file mode 100644 index 0000000..897ba62 --- /dev/null +++ b/src/mppe.c @@ -0,0 +1,817 @@ +/*- + * Copyright (c) 2000 Semen Ustimenko <semenu@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/usr.sbin/ppp/mppe.c,v 1.28.26.1 2010/12/21 17:10:29 kensmith Exp $ + */ + +#include <sys/param.h> + +#include <sys/socket.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <sys/un.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <openssl/rc4.h> + +#include "defs.h" +#include "mbuf.h" +#include "log.h" +#include "timer.h" +#include "fsm.h" +#include "lqr.h" +#include "hdlc.h" +#include "lcp.h" +#include "ccp.h" +#include "throughput.h" +#include "layer.h" +#include "link.h" +#include "chap_ms.h" +#include "proto.h" +#include "mppe.h" +#include "ua.h" +#include "descriptor.h" +#ifndef NORADIUS +#include "radius.h" +#endif +#include "ncpaddr.h" +#include "iplist.h" +#include "slcompress.h" +#include "ipcp.h" +#include "ipv6cp.h" +#include "filter.h" +#include "mp.h" +#include "ncp.h" +#include "bundle.h" + +/* + * Documentation: + * + * draft-ietf-pppext-mppe-04.txt + * draft-ietf-pppext-mppe-keys-02.txt + */ + +#define MPPE_OPT_STATELESS 0x1000000 +#define MPPE_OPT_COMPRESSED 0x01 +#define MPPE_OPT_40BIT 0x20 +#define MPPE_OPT_56BIT 0x80 +#define MPPE_OPT_128BIT 0x40 +#define MPPE_OPT_BITMASK 0xe0 +#define MPPE_OPT_MASK (MPPE_OPT_STATELESS | MPPE_OPT_BITMASK) + +#define MPPE_FLUSHED 0x8000 +#define MPPE_ENCRYPTED 0x1000 +#define MPPE_HEADER_BITMASK 0xf000 +#define MPPE_HEADER_FLAG 0x00ff +#define MPPE_HEADER_FLAGMASK 0x00ff +#define MPPE_HEADER_FLAGSHIFT 8 +#define MPPE_HEADER_STATEFUL_KEYCHANGES 16 + +struct mppe_state { + unsigned stateless : 1; + unsigned flushnext : 1; + unsigned flushrequired : 1; + int cohnum; + unsigned keylen; /* 8 or 16 bytes */ + int keybits; /* 40, 56 or 128 bits */ + char sesskey[MPPE_KEY_LEN]; + char mastkey[MPPE_KEY_LEN]; + RC4_KEY rc4key; +}; + +int MPPE_MasterKeyValid = 0; +int MPPE_IsServer = 0; +char MPPE_MasterKey[MPPE_KEY_LEN]; + +/* + * The peer has missed a packet. Mark the next output frame to be FLUSHED + */ +static int +MPPEResetOutput(void *v) +{ + struct mppe_state *mop = (struct mppe_state *)v; + + if (mop->stateless) + log_Printf(LogCCP, "MPPE: Unexpected output channel reset\n"); + else { + log_Printf(LogCCP, "MPPE: Output channel reset\n"); + mop->flushnext = 1; + } + + return 0; /* Ask FSM not to ACK */ +} + +static void +MPPEReduceSessionKey(struct mppe_state *mp) +{ + switch(mp->keybits) { + case 40: + mp->sesskey[2] = 0x9e; + mp->sesskey[1] = 0x26; + case 56: + mp->sesskey[0] = 0xd1; + case 128: + break; + } +} + +static void +MPPEKeyChange(struct mppe_state *mp) +{ + char InterimKey[MPPE_KEY_LEN]; + RC4_KEY RC4Key; + + GetNewKeyFromSHA(mp->mastkey, mp->sesskey, mp->keylen, InterimKey); + RC4_set_key(&RC4Key, mp->keylen, InterimKey); + RC4(&RC4Key, mp->keylen, InterimKey, mp->sesskey); + + MPPEReduceSessionKey(mp); +} + +static struct mbuf * +MPPEOutput(void *v, struct ccp *ccp, struct link *l __unused, int pri __unused, + u_short *proto, struct mbuf *mp) +{ + struct mppe_state *mop = (struct mppe_state *)v; + struct mbuf *mo; + u_short nproto, prefix; + int dictinit, ilen, len; + char *rp; + + ilen = m_length(mp); + dictinit = 0; + + log_Printf(LogDEBUG, "MPPE: Output: Proto %02x (%d bytes)\n", *proto, ilen); + if (*proto < 0x21 && *proto > 0xFA) { + log_Printf(LogDEBUG, "MPPE: Output: Not encrypting\n"); + ccp->compout += ilen; + ccp->uncompout += ilen; + return mp; + } + + log_DumpBp(LogDEBUG, "MPPE: Output: Encrypt packet:", mp); + + /* Get mbuf for prefixes */ + mo = m_get(4, MB_CCPOUT); + mo->m_next = mp; + + rp = MBUF_CTOP(mo); + prefix = MPPE_ENCRYPTED | mop->cohnum; + + if (mop->stateless || + (mop->cohnum & MPPE_HEADER_FLAGMASK) == MPPE_HEADER_FLAG) { + /* Change our key */ + log_Printf(LogDEBUG, "MPPEOutput: Key changed [%d]\n", mop->cohnum); + MPPEKeyChange(mop); + dictinit = 1; + } + + if (mop->stateless || mop->flushnext) { + prefix |= MPPE_FLUSHED; + dictinit = 1; + mop->flushnext = 0; + } + + if (dictinit) { + /* Initialise our dictionary */ + log_Printf(LogDEBUG, "MPPEOutput: Dictionary initialised [%d]\n", + mop->cohnum); + RC4_set_key(&mop->rc4key, mop->keylen, mop->sesskey); + } + + /* Set MPPE packet prefix */ + ua_htons(&prefix, rp); + + /* Save encrypted protocol number */ + nproto = htons(*proto); + RC4(&mop->rc4key, 2, (char *)&nproto, rp + 2); + + /* Encrypt main packet */ + rp = MBUF_CTOP(mp); + RC4(&mop->rc4key, ilen, rp, rp); + + mop->cohnum++; + mop->cohnum &= ~MPPE_HEADER_BITMASK; + + /* Set the protocol number */ + *proto = ccp_Proto(ccp); + len = m_length(mo); + ccp->uncompout += ilen; + ccp->compout += len; + + log_Printf(LogDEBUG, "MPPE: Output: Encrypted: Proto %02x (%d bytes)\n", + *proto, len); + + return mo; +} + +static void +MPPEResetInput(void *v __unused) +{ + log_Printf(LogCCP, "MPPE: Unexpected input channel ack\n"); +} + +static struct mbuf * +MPPEInput(void *v, struct ccp *ccp, u_short *proto, struct mbuf *mp) +{ + struct mppe_state *mip = (struct mppe_state *)v; + u_short prefix; + char *rp; + int dictinit, flushed, ilen, len, n; + + ilen = m_length(mp); + dictinit = 0; + ccp->compin += ilen; + + log_Printf(LogDEBUG, "MPPE: Input: Proto %02x (%d bytes)\n", *proto, ilen); + log_DumpBp(LogDEBUG, "MPPE: Input: Packet:", mp); + + mp = mbuf_Read(mp, &prefix, 2); + prefix = ntohs(prefix); + flushed = prefix & MPPE_FLUSHED; + prefix &= ~flushed; + if ((prefix & MPPE_HEADER_BITMASK) != MPPE_ENCRYPTED) { + log_Printf(LogERROR, "MPPE: Input: Invalid packet (flags = 0x%x)\n", + (prefix & MPPE_HEADER_BITMASK) | flushed); + m_freem(mp); + return NULL; + } + + prefix &= ~MPPE_HEADER_BITMASK; + + if (!flushed && mip->stateless) { + log_Printf(LogCCP, "MPPEInput: Packet without MPPE_FLUSHED set" + " in stateless mode\n"); + flushed = MPPE_FLUSHED; + /* Should we really continue ? */ + } + + if (mip->stateless) { + /* Change our key for each missed packet in stateless mode */ + while (prefix != mip->cohnum) { + log_Printf(LogDEBUG, "MPPEInput: Key changed [%u]\n", prefix); + MPPEKeyChange(mip); + /* + * mip->cohnum contains what we received last time in stateless + * mode. + */ + mip->cohnum++; + mip->cohnum &= ~MPPE_HEADER_BITMASK; + } + dictinit = 1; + } else { + if (flushed) { + /* + * We can always process a flushed packet. + * Catch up on any outstanding key changes. + */ + n = (prefix >> MPPE_HEADER_FLAGSHIFT) - + (mip->cohnum >> MPPE_HEADER_FLAGSHIFT); + if (n < 0) + n += MPPE_HEADER_STATEFUL_KEYCHANGES; + while (n--) { + log_Printf(LogDEBUG, "MPPEInput: Key changed during catchup [%u]\n", + prefix); + MPPEKeyChange(mip); + } + mip->flushrequired = 0; + mip->cohnum = prefix; + dictinit = 1; + } + + if (mip->flushrequired) { + /* + * Perhaps we should be lenient if + * (prefix & MPPE_HEADER_FLAGMASK) == MPPE_HEADER_FLAG + * The spec says that we shouldn't be though.... + */ + log_Printf(LogDEBUG, "MPPE: Not flushed - discarded\n"); + fsm_Output(&ccp->fsm, CODE_RESETREQ, ccp->fsm.reqid++, NULL, 0, + MB_CCPOUT); + m_freem(mp); + return NULL; + } + + if (prefix != mip->cohnum) { + /* + * We're in stateful mode and didn't receive the expected + * packet. Send a reset request, but don't tell the CCP layer + * about it as we don't expect to receive a Reset ACK ! + * Guess what... M$ invented this ! + */ + log_Printf(LogCCP, "MPPE: Input: Got seq %u, not %u\n", + prefix, mip->cohnum); + fsm_Output(&ccp->fsm, CODE_RESETREQ, ccp->fsm.reqid++, NULL, 0, + MB_CCPOUT); + mip->flushrequired = 1; + m_freem(mp); + return NULL; + } + + if ((prefix & MPPE_HEADER_FLAGMASK) == MPPE_HEADER_FLAG) { + log_Printf(LogDEBUG, "MPPEInput: Key changed [%u]\n", prefix); + MPPEKeyChange(mip); + dictinit = 1; + } else if (flushed) + dictinit = 1; + + /* + * mip->cohnum contains what we expect to receive next time in stateful + * mode. + */ + mip->cohnum++; + mip->cohnum &= ~MPPE_HEADER_BITMASK; + } + + if (dictinit) { + log_Printf(LogDEBUG, "MPPEInput: Dictionary initialised [%u]\n", prefix); + RC4_set_key(&mip->rc4key, mip->keylen, mip->sesskey); + } + + mp = mbuf_Read(mp, proto, 2); + RC4(&mip->rc4key, 2, (char *)proto, (char *)proto); + *proto = ntohs(*proto); + + rp = MBUF_CTOP(mp); + len = m_length(mp); + RC4(&mip->rc4key, len, rp, rp); + + log_Printf(LogDEBUG, "MPPEInput: Decrypted: Proto %02x (%d bytes)\n", + *proto, len); + log_DumpBp(LogDEBUG, "MPPEInput: Decrypted: Packet:", mp); + + ccp->uncompin += len; + + return mp; +} + +static void +MPPEDictSetup(void *v __unused, struct ccp *ccp __unused, + u_short proto __unused, struct mbuf *mp __unused) +{ + /* Nothing to see here */ +} + +static const char * +MPPEDispOpts(struct fsm_opt *o) +{ + static char buf[70]; + u_int32_t val; + char ch; + int len, n; + + ua_ntohl(o->data, &val); + len = 0; + if ((n = snprintf(buf, sizeof buf, "value 0x%08x ", (unsigned)val)) > 0) + len += n; + if (!(val & MPPE_OPT_BITMASK)) { + if ((n = snprintf(buf + len, sizeof buf - len, "(0")) > 0) + len += n; + } else { + ch = '('; + if (val & MPPE_OPT_128BIT) { + if ((n = snprintf(buf + len, sizeof buf - len, "%c128", ch)) > 0) + len += n; + ch = '/'; + } + if (val & MPPE_OPT_56BIT) { + if ((n = snprintf(buf + len, sizeof buf - len, "%c56", ch)) > 0) + len += n; + ch = '/'; + } + if (val & MPPE_OPT_40BIT) { + if ((n = snprintf(buf + len, sizeof buf - len, "%c40", ch)) > 0) + len += n; + ch = '/'; + } + } + + if ((n = snprintf(buf + len, sizeof buf - len, " bits, state%s", + (val & MPPE_OPT_STATELESS) ? "less" : "ful")) > 0) + len += n; + + if (val & MPPE_OPT_COMPRESSED) { + if ((n = snprintf(buf + len, sizeof buf - len, ", compressed")) > 0) + len += n; + } + + snprintf(buf + len, sizeof buf - len, ")"); + + return buf; +} + +static int +MPPEUsable(struct fsm *fp) +{ + int ok; +#ifndef NORADIUS + struct radius *r = &fp->bundle->radius; + + /* + * If the radius server gave us RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES, + * use that instead of our configuration value. + */ + if (*r->cfg.file) { + ok = r->mppe.sendkeylen && r->mppe.recvkeylen; + if (!ok) + log_Printf(LogCCP, "MPPE: Not permitted by RADIUS server\n"); + } else +#endif + { + struct lcp *lcp = &fp->link->lcp; + ok = (lcp->want_auth == PROTO_CHAP && lcp->want_authtype == 0x81) || + (lcp->his_auth == PROTO_CHAP && lcp->his_authtype == 0x81); + if (!ok) + log_Printf(LogCCP, "MPPE: Not usable without CHAP81\n"); + } + + return ok; +} + +static int +MPPERequired(struct fsm *fp) +{ +#ifndef NORADIUS + /* + * If the radius server gave us RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY, + * use that instead of our configuration value. + */ + if (*fp->bundle->radius.cfg.file && fp->bundle->radius.mppe.policy) + return fp->bundle->radius.mppe.policy == MPPE_POLICY_REQUIRED ? 1 : 0; +#endif + + return fp->link->ccp.cfg.mppe.required; +} + +static u_int32_t +MPPE_ConfigVal(struct bundle *bundle __unused, const struct ccp_config *cfg) +{ + u_int32_t val; + + val = cfg->mppe.state == MPPE_STATELESS ? MPPE_OPT_STATELESS : 0; +#ifndef NORADIUS + /* + * If the radius server gave us RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES, + * use that instead of our configuration value. + */ + if (*bundle->radius.cfg.file && bundle->radius.mppe.types) { + if (bundle->radius.mppe.types & MPPE_TYPE_40BIT) + val |= MPPE_OPT_40BIT; + if (bundle->radius.mppe.types & MPPE_TYPE_128BIT) + val |= MPPE_OPT_128BIT; + } else +#endif + switch(cfg->mppe.keybits) { + case 128: + val |= MPPE_OPT_128BIT; + break; + case 56: + val |= MPPE_OPT_56BIT; + break; + case 40: + val |= MPPE_OPT_40BIT; + break; + case 0: + val |= MPPE_OPT_128BIT | MPPE_OPT_56BIT | MPPE_OPT_40BIT; + break; + } + + return val; +} + +/* + * What options should we use for our first configure request + */ +static void +MPPEInitOptsOutput(struct bundle *bundle, struct fsm_opt *o, + const struct ccp_config *cfg) +{ + u_int32_t mval; + + o->hdr.len = 6; + + if (!MPPE_MasterKeyValid) { + log_Printf(LogCCP, "MPPE: MasterKey is invalid," + " MPPE is available only with CHAP81 authentication\n"); + mval = 0; + ua_htonl(&mval, o->data); + return; + } + + + mval = MPPE_ConfigVal(bundle, cfg); + ua_htonl(&mval, o->data); +} + +/* + * Our CCP request was NAK'd with the given options + */ +static int +MPPESetOptsOutput(struct bundle *bundle, struct fsm_opt *o, + const struct ccp_config *cfg) +{ + u_int32_t mval, peer; + + ua_ntohl(o->data, &peer); + + if (!MPPE_MasterKeyValid) + /* Treat their NAK as a REJ */ + return MODE_NAK; + + mval = MPPE_ConfigVal(bundle, cfg); + + /* + * If we haven't been configured with a specific number of keybits, allow + * whatever the peer asks for. + */ + if (!cfg->mppe.keybits) { + mval &= ~MPPE_OPT_BITMASK; + mval |= (peer & MPPE_OPT_BITMASK); + if (!(mval & MPPE_OPT_BITMASK)) + mval |= MPPE_OPT_128BIT; + } + + /* Adjust our statelessness */ + if (cfg->mppe.state == MPPE_ANYSTATE) { + mval &= ~MPPE_OPT_STATELESS; + mval |= (peer & MPPE_OPT_STATELESS); + } + + ua_htonl(&mval, o->data); + + return MODE_ACK; +} + +/* + * The peer has requested the given options + */ +static int +MPPESetOptsInput(struct bundle *bundle, struct fsm_opt *o, + const struct ccp_config *cfg) +{ + u_int32_t mval, peer; + int res = MODE_ACK; + + ua_ntohl(o->data, &peer); + if (!MPPE_MasterKeyValid) { + if (peer != 0) { + peer = 0; + ua_htonl(&peer, o->data); + return MODE_NAK; + } else + return MODE_ACK; + } + + mval = MPPE_ConfigVal(bundle, cfg); + + if (peer & ~MPPE_OPT_MASK) + /* He's asking for bits we don't know about */ + res = MODE_NAK; + + if (peer & MPPE_OPT_STATELESS) { + if (cfg->mppe.state == MPPE_STATEFUL) + /* Peer can't have stateless */ + res = MODE_NAK; + else + /* Peer wants stateless, that's ok */ + mval |= MPPE_OPT_STATELESS; + } else { + if (cfg->mppe.state == MPPE_STATELESS) + /* Peer must have stateless */ + res = MODE_NAK; + else + /* Peer doesn't want stateless, that's ok */ + mval &= ~MPPE_OPT_STATELESS; + } + + /* If we've got a configured number of keybits - the peer must use that */ + if (cfg->mppe.keybits) { + ua_htonl(&mval, o->data); + return peer == mval ? res : MODE_NAK; + } + + /* If a specific number of bits hasn't been requested, we'll need to NAK */ + switch (peer & MPPE_OPT_BITMASK) { + case MPPE_OPT_128BIT: + case MPPE_OPT_56BIT: + case MPPE_OPT_40BIT: + break; + default: + res = MODE_NAK; + } + + /* Suggest the best number of bits */ + mval &= ~MPPE_OPT_BITMASK; + if (peer & MPPE_OPT_128BIT) + mval |= MPPE_OPT_128BIT; + else if (peer & MPPE_OPT_56BIT) + mval |= MPPE_OPT_56BIT; + else if (peer & MPPE_OPT_40BIT) + mval |= MPPE_OPT_40BIT; + else + mval |= MPPE_OPT_128BIT; + ua_htonl(&mval, o->data); + + return res; +} + +static struct mppe_state * +MPPE_InitState(struct fsm_opt *o) +{ + struct mppe_state *mp; + u_int32_t val; + + if ((mp = calloc(1, sizeof *mp)) != NULL) { + ua_ntohl(o->data, &val); + + switch (val & MPPE_OPT_BITMASK) { + case MPPE_OPT_128BIT: + mp->keylen = 16; + mp->keybits = 128; + break; + case MPPE_OPT_56BIT: + mp->keylen = 8; + mp->keybits = 56; + break; + case MPPE_OPT_40BIT: + mp->keylen = 8; + mp->keybits = 40; + break; + default: + log_Printf(LogWARN, "Unexpected MPPE options 0x%08x\n", val); + free(mp); + return NULL; + } + + mp->stateless = !!(val & MPPE_OPT_STATELESS); + } + + return mp; +} + +static void * +MPPEInitInput(struct bundle *bundle __unused, struct fsm_opt *o) +{ + struct mppe_state *mip; + + if (!MPPE_MasterKeyValid) { + log_Printf(LogWARN, "MPPE: Cannot initialise without CHAP81\n"); + return NULL; + } + + if ((mip = MPPE_InitState(o)) == NULL) { + log_Printf(LogWARN, "MPPEInput: Cannot initialise - unexpected options\n"); + return NULL; + } + + log_Printf(LogDEBUG, "MPPE: InitInput: %d-bits\n", mip->keybits); + +#ifndef NORADIUS + if (*bundle->radius.cfg.file && bundle->radius.mppe.recvkey) { + if (mip->keylen > bundle->radius.mppe.recvkeylen) + mip->keylen = bundle->radius.mppe.recvkeylen; + if (mip->keylen > sizeof mip->mastkey) + mip->keylen = sizeof mip->mastkey; + memcpy(mip->mastkey, bundle->radius.mppe.recvkey, mip->keylen); + } else +#endif + GetAsymetricStartKey(MPPE_MasterKey, mip->mastkey, mip->keylen, 0, + MPPE_IsServer); + + GetNewKeyFromSHA(mip->mastkey, mip->mastkey, mip->keylen, mip->sesskey); + + MPPEReduceSessionKey(mip); + + log_Printf(LogCCP, "MPPE: Input channel initiated\n"); + + if (!mip->stateless) { + /* + * We need to initialise our dictionary here as the first packet we + * receive is unlikely to have the FLUSHED bit set. + */ + log_Printf(LogDEBUG, "MPPEInitInput: Dictionary initialised [%d]\n", + mip->cohnum); + RC4_set_key(&mip->rc4key, mip->keylen, mip->sesskey); + } else { + /* + * We do the first key change here as the first packet is expected + * to have a sequence number of 0 and we'll therefore not expect + * to have to change the key at that point. + */ + log_Printf(LogDEBUG, "MPPEInitInput: Key changed [%d]\n", mip->cohnum); + MPPEKeyChange(mip); + } + + return mip; +} + +static void * +MPPEInitOutput(struct bundle *bundle __unused, struct fsm_opt *o) +{ + struct mppe_state *mop; + + if (!MPPE_MasterKeyValid) { + log_Printf(LogWARN, "MPPE: Cannot initialise without CHAP81\n"); + return NULL; + } + + if ((mop = MPPE_InitState(o)) == NULL) { + log_Printf(LogWARN, "MPPEOutput: Cannot initialise - unexpected options\n"); + return NULL; + } + + log_Printf(LogDEBUG, "MPPE: InitOutput: %d-bits\n", mop->keybits); + +#ifndef NORADIUS + if (*bundle->radius.cfg.file && bundle->radius.mppe.sendkey) { + if (mop->keylen > bundle->radius.mppe.sendkeylen) + mop->keylen = bundle->radius.mppe.sendkeylen; + if (mop->keylen > sizeof mop->mastkey) + mop->keylen = sizeof mop->mastkey; + memcpy(mop->mastkey, bundle->radius.mppe.sendkey, mop->keylen); + } else +#endif + GetAsymetricStartKey(MPPE_MasterKey, mop->mastkey, mop->keylen, 1, + MPPE_IsServer); + + GetNewKeyFromSHA(mop->mastkey, mop->mastkey, mop->keylen, mop->sesskey); + + MPPEReduceSessionKey(mop); + + log_Printf(LogCCP, "MPPE: Output channel initiated\n"); + + if (!mop->stateless) { + /* + * We need to initialise our dictionary now as the first packet we + * send won't have the FLUSHED bit set. + */ + log_Printf(LogDEBUG, "MPPEInitOutput: Dictionary initialised [%d]\n", + mop->cohnum); + RC4_set_key(&mop->rc4key, mop->keylen, mop->sesskey); + } + + return mop; +} + +static void +MPPETermInput(void *v) +{ + free(v); +} + +static void +MPPETermOutput(void *v) +{ + free(v); +} + +const struct ccp_algorithm MPPEAlgorithm = { + TY_MPPE, + CCP_NEG_MPPE, + MPPEDispOpts, + MPPEUsable, + MPPERequired, + { + MPPESetOptsInput, + MPPEInitInput, + MPPETermInput, + MPPEResetInput, + MPPEInput, + MPPEDictSetup + }, + { + 2, + MPPEInitOptsOutput, + MPPESetOptsOutput, + MPPEInitOutput, + MPPETermOutput, + MPPEResetOutput, + MPPEOutput + }, +}; |