summaryrefslogtreecommitdiff
path: root/usr.sbin/ppp/mppe.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/ppp/mppe.c')
-rw-r--r--usr.sbin/ppp/mppe.c530
1 files changed, 404 insertions, 126 deletions
diff --git a/usr.sbin/ppp/mppe.c b/usr.sbin/ppp/mppe.c
index 617596a816bf..5b32d1b0f42b 100644
--- a/usr.sbin/ppp/mppe.c
+++ b/usr.sbin/ppp/mppe.c
@@ -30,6 +30,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <termios.h>
#ifdef __FreeBSD__
#include <sha.h>
@@ -61,23 +62,53 @@
* 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
+
struct mppe_state {
- int cohnum;
- int 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;
+ unsigned stateless : 1;
+ unsigned flushnext : 1;
+ unsigned flushrequired : 1;
+ int cohnum;
+ int 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];
-static void
+/*
+ * The peer has missed a packet. Mark the next output frame to be FLUSHED
+ */
+static int
MPPEResetOutput(void *v)
{
- log_Printf(LogCCP, "MPPE: Output channel reset\n");
+ 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
@@ -112,17 +143,18 @@ MPPEOutput(void *v, struct ccp *ccp, struct link *l, int pri, u_short *proto,
{
struct mppe_state *mop = (struct mppe_state *)v;
struct mbuf *mo;
- u_short nproto;
- int ilen;
+ u_short nproto, prefix;
+ int dictinit, ilen, len;
char *rp;
- log_Printf(LogCCP, "MPPE: Output\n");
-
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;
}
@@ -132,12 +164,32 @@ MPPEOutput(void *v, struct ccp *ccp, struct link *l, int pri, u_short *proto,
mo = m_get(4, MB_CCPOUT);
mo->m_next = mp;
- /* Init RC4 keys */
- RC4_set_key(&mop->rc4key, mop->keylen, mop->sesskey);
+ 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 */
- rp = MBUF_CTOP(mo);
- *(u_short *)rp = htons(0x9000 | mop->cohnum);
+ *(u_short *)rp = htons(prefix);
/* Save encrypted protocol number */
nproto = htons(*proto);
@@ -147,15 +199,17 @@ MPPEOutput(void *v, struct ccp *ccp, struct link *l, int pri, u_short *proto,
rp = MBUF_CTOP(mp);
RC4(&mop->rc4key, ilen, rp, rp);
- /* Rotate keys */
- MPPEKeyChange(mop);
- mop->cohnum ++; mop->cohnum &= 0xFFF;
+ mop->cohnum++;
+ mop->cohnum &= ~MPPE_HEADER_BITMASK;
- /* Chage protocol number */
+ /* 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, m_length(mo));
+ *proto, len);
return mo;
}
@@ -163,7 +217,7 @@ MPPEOutput(void *v, struct ccp *ccp, struct link *l, int pri, u_short *proto,
static void
MPPEResetInput(void *v)
{
- log_Printf(LogCCP, "MPPE: Input channel reset\n");
+ log_Printf(LogCCP, "MPPE: Unexpected input channel ack\n");
}
static struct mbuf *
@@ -172,43 +226,126 @@ 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 ilen;
-
- log_Printf(LogCCP, "MPPE: Input\n");
+ 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);
- if ((prefix & 0xF000) != 0x9000) {
- log_Printf(LogERROR, "MPPE: Input: Invalid packet\n");
+ 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 &= 0xFFF;
- while (prefix != mip->cohnum) {
- MPPEKeyChange(mip);
- mip->cohnum ++; mip->cohnum &= 0xFFF;
+ 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);
+ 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");
+ 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;
}
- RC4_set_key(&mip->rc4key, mip->keylen, mip->sesskey);
+ 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);
- RC4(&mip->rc4key, m_length(mp), rp, rp);
+ len = m_length(mp);
+ RC4(&mip->rc4key, len, rp, rp);
- log_Printf(LogDEBUG, "MPPE: Input: Decrypted: Proto %02x (%d bytes)\n",
- *proto, m_length(mp));
+ log_Printf(LogDEBUG, "MPPEInput: Decrypted: Proto %02x (%d bytes)\n",
+ *proto, len);
+ log_DumpBp(LogDEBUG, "MPPEInput: Decrypted: Packet:", mp);
- log_DumpBp(LogDEBUG, "MPPE: Input: Decrypted: Packet:", mp);
+ ccp->uncompin += len;
return mp;
}
@@ -216,14 +353,51 @@ MPPEInput(void *v, struct ccp *ccp, u_short *proto, struct mbuf *mp)
static void
MPPEDictSetup(void *v, struct ccp *ccp, u_short proto, struct mbuf *mi)
{
- log_Printf(LogCCP, "MPPE: DictSetup\n");
}
static const char *
MPPEDispOpts(struct lcp_opt *o)
{
- static char buf[32];
- sprintf(buf, "value 0x%08x", (int)ntohl(*(u_int32_t *)(o->data)));
+ static char buf[70];
+ u_int32_t val = ntohl(*(u_int32_t *)o->data);
+ char ch;
+ int len;
+
+ snprintf(buf, sizeof buf, "value 0x%08x ", (unsigned)val);
+ len = strlen(buf);
+ if (!(val & MPPE_OPT_BITMASK)) {
+ snprintf(buf + len, sizeof buf - len, "(0");
+ len++;
+ } else {
+ ch = '(';
+ if (val & MPPE_OPT_128BIT) {
+ snprintf(buf + len, sizeof buf - len, "%c128", ch);
+ len += strlen(buf + len);
+ ch = '/';
+ }
+ if (val & MPPE_OPT_56BIT) {
+ snprintf(buf + len, sizeof buf - len, "%c56", ch);
+ len += strlen(buf + len);
+ ch = '/';
+ }
+ if (val & MPPE_OPT_40BIT) {
+ snprintf(buf + len, sizeof buf - len, "%c40", ch);
+ len += strlen(buf + len);
+ ch = '/';
+ }
+ }
+
+ snprintf(buf + len, sizeof buf - len, " bits, state%s",
+ (val & MPPE_OPT_STATELESS) ? "less" : "full");
+ len += strlen(buf + len);
+
+ if (val & MPPE_OPT_COMPRESSED) {
+ snprintf(buf + len, sizeof buf - len, ", compressed");
+ len += strlen(buf + len);
+ }
+
+ snprintf(buf + len, sizeof buf - len, ")");
+
return buf;
}
@@ -242,120 +416,213 @@ MPPEUsable(struct fsm *fp)
return ok;
}
+static int
+MPPERequired(struct fsm *fp)
+{
+ return fp->link->ccp.cfg.mppe.required;
+}
+
+static u_int32_t
+MPPE_ConfigVal(const struct ccp_config *cfg)
+{
+ u_int32_t val;
+
+ val = cfg->mppe.state == MPPE_STATELESS ? MPPE_OPT_STATELESS : 0;
+ 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 lcp_opt *o, const struct ccp_config *cfg)
{
- u_long val;
+ u_int32_t *p = (u_int32_t *)o->data;
o->len = 6;
- log_Printf(LogCCP, "MPPE: InitOptsOutput\n");
-
if (!MPPE_MasterKeyValid) {
log_Printf(LogCCP, "MPPE: MasterKey is invalid,"
" MPPE is available only with CHAP81 authentication\n");
- *(u_int32_t *)o->data = htonl(0x0);
+ *p = htonl(0x0);
return;
}
- val = 0x1000000;
- switch(cfg->mppe.keybits) {
- case 128:
- val |= 0x40; break;
- case 56:
- val |= 0x80; break;
- case 40:
- val |= 0x20; break;
- }
- *(u_int32_t *)o->data = htonl(val);
+ *p = htonl(MPPE_ConfigVal(cfg));
}
+/*
+ * Our CCP request was NAK'd with the given options
+ */
static int
-MPPESetOptsOutput(struct lcp_opt *o)
+MPPESetOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg)
{
- u_long *p = (u_long *)(o->data);
- u_long val = ntohl(*p);
-
- log_Printf(LogCCP, "MPPE: SetOptsOutput\n");
+ u_int32_t *p = (u_int32_t *)o->data;
+ u_int32_t peer = ntohl(*p);
+ u_int32_t mval;
+
+ if (!MPPE_MasterKeyValid)
+ /* Treat their NAK as a REJ */
+ return MODE_NAK;
+
+ mval = MPPE_ConfigVal(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;
+ }
- if (!MPPE_MasterKeyValid) {
- if (*p != 0x0) {
- *p = 0x0;
- return MODE_NAK;
- } else {
- return MODE_ACK;
- }
+ /* Adjust our statelessness */
+ if (cfg->mppe.state == MPPE_ANYSTATE) {
+ mval &= ~MPPE_OPT_STATELESS;
+ mval |= (peer & MPPE_OPT_STATELESS);
}
- if (val == 0x01000020 ||
- val == 0x01000040 ||
- val == 0x01000080)
- return MODE_ACK;
+ *p = htonl(mval);
- return MODE_NAK;
+ return MODE_ACK;
}
+/*
+ * The peer has requested the given options
+ */
static int
MPPESetOptsInput(struct lcp_opt *o, const struct ccp_config *cfg)
{
- u_long *p = (u_long *)(o->data);
- u_long val = ntohl(*p);
- u_long mval;
-
- log_Printf(LogCCP, "MPPE: SetOptsInput\n");
+ u_int32_t *p = (u_int32_t *)(o->data);
+ u_int32_t peer = ntohl(*p);
+ u_int32_t mval;
+ int res = MODE_ACK;
if (!MPPE_MasterKeyValid) {
if (*p != 0x0) {
*p = 0x0;
return MODE_NAK;
- } else {
+ } else
return MODE_ACK;
- }
}
- mval = 0x01000000;
- switch(cfg->mppe.keybits) {
- case 128:
- mval |= 0x40; break;
- case 56:
- mval |= 0x80; break;
- case 40:
- mval |= 0x20; break;
+ mval = MPPE_ConfigVal(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 (val == mval)
- return MODE_ACK;
+ /* If we've got a configured number of keybits - the peer must use that */
+ if (cfg->mppe.keybits) {
+ *p = htonl(mval);
+ 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;
*p = htonl(mval);
- return MODE_NAK;
+ return res;
+}
+
+static struct mppe_state *
+MPPE_InitState(struct lcp_opt *o)
+{
+ struct mppe_state *mp;
+ u_int32_t val;
+
+ if ((mp = calloc(1, sizeof *mp)) != NULL) {
+ val = ntohl(*(u_int32_t *)o->data);
+
+ 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 lcp_opt *o)
{
struct mppe_state *mip;
- u_int32_t val = ntohl(*(unsigned long *)o->data);
-
- log_Printf(LogCCP, "MPPE: InitInput\n");
if (!MPPE_MasterKeyValid) {
log_Printf(LogWARN, "MPPE: Cannot initialise without CHAP81\n");
return NULL;
}
- mip = malloc(sizeof(*mip));
- memset(mip, 0, sizeof(*mip));
-
- if (val & 0x20) { /* 40-bits */
- mip->keylen = 8;
- mip->keybits = 40;
- } else if (val & 0x80) { /* 56-bits */
- mip->keylen = 8;
- mip->keybits = 56;
- } else { /* 128-bits */
- mip->keylen = 16;
- mip->keybits = 128;
+ 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);
@@ -366,9 +633,25 @@ MPPEInitInput(struct lcp_opt *o)
MPPEReduceSessionKey(mip);
- MPPEKeyChange(mip);
-
- mip->cohnum = 0;
+ 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;
}
@@ -377,27 +660,15 @@ static void *
MPPEInitOutput(struct lcp_opt *o)
{
struct mppe_state *mop;
- u_int32_t val = ntohl(*(unsigned long *)o->data);
-
- log_Printf(LogCCP, "MPPE: InitOutput\n");
if (!MPPE_MasterKeyValid) {
log_Printf(LogWARN, "MPPE: Cannot initialise without CHAP81\n");
return NULL;
}
- mop = malloc(sizeof(*mop));
- memset(mop, 0, sizeof(*mop));
-
- if (val & 0x20) { /* 40-bits */
- mop->keylen = 8;
- mop->keybits = 40;
- } else if (val & 0x80) { /* 56-bits */
- mop->keylen = 8;
- mop->keybits = 56;
- } else { /* 128-bits */
- mop->keylen = 16;
- mop->keybits = 128;
+ 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);
@@ -408,9 +679,17 @@ MPPEInitOutput(struct lcp_opt *o)
MPPEReduceSessionKey(mop);
- MPPEKeyChange(mop);
+ log_Printf(LogCCP, "MPPE: Output channel initiated\n");
- mop->cohnum = 0;
+ 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;
}
@@ -418,14 +697,12 @@ MPPEInitOutput(struct lcp_opt *o)
static void
MPPETermInput(void *v)
{
- log_Printf(LogCCP, "MPPE: TermInput\n");
free(v);
}
static void
MPPETermOutput(void *v)
{
- log_Printf(LogCCP, "MPPE: TermOutput\n");
free(v);
}
@@ -434,6 +711,7 @@ const struct ccp_algorithm MPPEAlgorithm = {
CCP_NEG_MPPE,
MPPEDispOpts,
MPPEUsable,
+ MPPERequired,
{
MPPESetOptsInput,
MPPEInitInput,