mppe.c revision 90868
1/*-
2 * Copyright (c) 2000 Semen Ustimenko <semenu@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/usr.sbin/ppp/mppe.c 90868 2002-02-18 20:35:27Z mike $
27 */
28
29#include <sys/types.h>
30
31#include <arpa/inet.h>
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <termios.h>
37#ifdef __FreeBSD__
38#include <sha.h>
39#else
40#include <openssl/sha.h>
41#endif
42#include <openssl/rc4.h>
43
44#include "defs.h"
45#include "mbuf.h"
46#include "log.h"
47#include "timer.h"
48#include "fsm.h"
49#include "lqr.h"
50#include "hdlc.h"
51#include "lcp.h"
52#include "ccp.h"
53#include "throughput.h"
54#include "layer.h"
55#include "link.h"
56#include "chap_ms.h"
57#include "proto.h"
58#include "mppe.h"
59#include "ua.h"
60
61/*
62 * Documentation:
63 *
64 * draft-ietf-pppext-mppe-04.txt
65 * draft-ietf-pppext-mppe-keys-02.txt
66 */
67
68#define	MPPE_OPT_STATELESS	0x1000000
69#define	MPPE_OPT_COMPRESSED	0x01
70#define	MPPE_OPT_40BIT		0x20
71#define	MPPE_OPT_56BIT		0x80
72#define	MPPE_OPT_128BIT		0x40
73#define	MPPE_OPT_BITMASK	0xe0
74#define	MPPE_OPT_MASK		(MPPE_OPT_STATELESS | MPPE_OPT_BITMASK)
75
76#define	MPPE_FLUSHED			0x8000
77#define	MPPE_ENCRYPTED			0x1000
78#define	MPPE_HEADER_BITMASK		0xf000
79#define	MPPE_HEADER_FLAG		0x00ff
80#define	MPPE_HEADER_FLAGMASK		0x00ff
81#define	MPPE_HEADER_FLAGSHIFT		8
82#define	MPPE_HEADER_STATEFUL_KEYCHANGES	16
83
84struct mppe_state {
85  unsigned	stateless : 1;
86  unsigned	flushnext : 1;
87  unsigned	flushrequired : 1;
88  int		cohnum;
89  int		keylen;			/* 8 or 16 bytes */
90  int 		keybits;		/* 40, 56 or 128 bits */
91  char		sesskey[MPPE_KEY_LEN];
92  char		mastkey[MPPE_KEY_LEN];
93  RC4_KEY	rc4key;
94};
95
96int MPPE_MasterKeyValid = 0;
97int MPPE_IsServer = 0;
98char MPPE_MasterKey[MPPE_KEY_LEN];
99
100/*
101 * The peer has missed a packet.  Mark the next output frame to be FLUSHED
102 */
103static int
104MPPEResetOutput(void *v)
105{
106  struct mppe_state *mop = (struct mppe_state *)v;
107
108  if (mop->stateless)
109    log_Printf(LogCCP, "MPPE: Unexpected output channel reset\n");
110  else {
111    log_Printf(LogCCP, "MPPE: Output channel reset\n");
112    mop->flushnext = 1;
113  }
114
115  return 0;		/* Ask FSM not to ACK */
116}
117
118static void
119MPPEReduceSessionKey(struct mppe_state *mp)
120{
121  switch(mp->keybits) {
122  case 40:
123    mp->sesskey[2] = 0x9e;
124    mp->sesskey[1] = 0x26;
125  case 56:
126    mp->sesskey[0] = 0xd1;
127  case 128:
128  }
129}
130
131static void
132MPPEKeyChange(struct mppe_state *mp)
133{
134  char InterimKey[MPPE_KEY_LEN];
135  RC4_KEY RC4Key;
136
137  GetNewKeyFromSHA(mp->mastkey, mp->sesskey, mp->keylen, InterimKey);
138  RC4_set_key(&RC4Key, mp->keylen, InterimKey);
139  RC4(&RC4Key, mp->keylen, InterimKey, mp->sesskey);
140
141  MPPEReduceSessionKey(mp);
142}
143
144static struct mbuf *
145MPPEOutput(void *v, struct ccp *ccp, struct link *l, int pri, u_short *proto,
146           struct mbuf *mp)
147{
148  struct mppe_state *mop = (struct mppe_state *)v;
149  struct mbuf *mo;
150  u_short nproto, prefix;
151  int dictinit, ilen, len;
152  char *rp;
153
154  ilen = m_length(mp);
155  dictinit = 0;
156
157  log_Printf(LogDEBUG, "MPPE: Output: Proto %02x (%d bytes)\n", *proto, ilen);
158  if (*proto < 0x21 && *proto > 0xFA) {
159    log_Printf(LogDEBUG, "MPPE: Output: Not encrypting\n");
160    ccp->compout += ilen;
161    ccp->uncompout += ilen;
162    return mp;
163  }
164
165  log_DumpBp(LogDEBUG, "MPPE: Output: Encrypt packet:", mp);
166
167  /* Get mbuf for prefixes */
168  mo = m_get(4, MB_CCPOUT);
169  mo->m_next = mp;
170
171  rp = MBUF_CTOP(mo);
172  prefix = MPPE_ENCRYPTED | mop->cohnum;
173
174  if (mop->stateless ||
175      (mop->cohnum & MPPE_HEADER_FLAGMASK) == MPPE_HEADER_FLAG) {
176    /* Change our key */
177    log_Printf(LogDEBUG, "MPPEOutput: Key changed [%d]\n", mop->cohnum);
178    MPPEKeyChange(mop);
179    dictinit = 1;
180  }
181
182  if (mop->stateless || mop->flushnext) {
183    prefix |= MPPE_FLUSHED;
184    dictinit = 1;
185    mop->flushnext = 0;
186  }
187
188  if (dictinit) {
189    /* Initialise our dictionary */
190    log_Printf(LogDEBUG, "MPPEOutput: Dictionary initialised [%d]\n",
191               mop->cohnum);
192    RC4_set_key(&mop->rc4key, mop->keylen, mop->sesskey);
193  }
194
195  /* Set MPPE packet prefix */
196  ua_htons(&prefix, rp);
197
198  /* Save encrypted protocol number */
199  nproto = htons(*proto);
200  RC4(&mop->rc4key, 2, (char *)&nproto, rp + 2);
201
202  /* Encrypt main packet */
203  rp = MBUF_CTOP(mp);
204  RC4(&mop->rc4key, ilen, rp, rp);
205
206  mop->cohnum++;
207  mop->cohnum &= ~MPPE_HEADER_BITMASK;
208
209  /* Set the protocol number */
210  *proto = ccp_Proto(ccp);
211  len = m_length(mo);
212  ccp->uncompout += ilen;
213  ccp->compout += len;
214
215  log_Printf(LogDEBUG, "MPPE: Output: Encrypted: Proto %02x (%d bytes)\n",
216             *proto, len);
217
218  return mo;
219}
220
221static void
222MPPEResetInput(void *v)
223{
224  log_Printf(LogCCP, "MPPE: Unexpected input channel ack\n");
225}
226
227static struct mbuf *
228MPPEInput(void *v, struct ccp *ccp, u_short *proto, struct mbuf *mp)
229{
230  struct mppe_state *mip = (struct mppe_state *)v;
231  u_short prefix;
232  char *rp;
233  int dictinit, flushed, ilen, len, n;
234
235  ilen = m_length(mp);
236  dictinit = 0;
237  ccp->compin += ilen;
238
239  log_Printf(LogDEBUG, "MPPE: Input: Proto %02x (%d bytes)\n", *proto, ilen);
240  log_DumpBp(LogDEBUG, "MPPE: Input: Packet:", mp);
241
242  mp = mbuf_Read(mp, &prefix, 2);
243  prefix = ntohs(prefix);
244  flushed = prefix & MPPE_FLUSHED;
245  prefix &= ~flushed;
246  if ((prefix & MPPE_HEADER_BITMASK) != MPPE_ENCRYPTED) {
247    log_Printf(LogERROR, "MPPE: Input: Invalid packet (flags = 0x%x)\n",
248               (prefix & MPPE_HEADER_BITMASK) | flushed);
249    m_freem(mp);
250    return NULL;
251  }
252
253  prefix &= ~MPPE_HEADER_BITMASK;
254
255  if (!flushed && mip->stateless) {
256    log_Printf(LogCCP, "MPPEInput: Packet without MPPE_FLUSHED set"
257               " in stateless mode\n");
258    flushed = MPPE_FLUSHED;
259    /* Should we really continue ? */
260  }
261
262  if (mip->stateless) {
263    /* Change our key for each missed packet in stateless mode */
264    while (prefix != mip->cohnum) {
265      log_Printf(LogDEBUG, "MPPEInput: Key changed [%u]\n", prefix);
266      MPPEKeyChange(mip);
267      /*
268       * mip->cohnum contains what we received last time in stateless
269       * mode.
270       */
271      mip->cohnum++;
272      mip->cohnum &= ~MPPE_HEADER_BITMASK;
273    }
274    dictinit = 1;
275  } else {
276    if (flushed) {
277      /*
278       * We can always process a flushed packet.
279       * Catch up on any outstanding key changes.
280       */
281      n = (prefix >> MPPE_HEADER_FLAGSHIFT) -
282          (mip->cohnum >> MPPE_HEADER_FLAGSHIFT);
283      if (n < 0)
284        n += MPPE_HEADER_STATEFUL_KEYCHANGES;
285      while (n--) {
286        log_Printf(LogDEBUG, "MPPEInput: Key changed during catchup [%u]\n",
287                   prefix);
288        MPPEKeyChange(mip);
289      }
290      mip->flushrequired = 0;
291      mip->cohnum = prefix;
292      dictinit = 1;
293    }
294
295    if (mip->flushrequired) {
296      /*
297       * Perhaps we should be lenient if
298       * (prefix & MPPE_HEADER_FLAGMASK) == MPPE_HEADER_FLAG
299       * The spec says that we shouldn't be though....
300       */
301      log_Printf(LogDEBUG, "MPPE: Not flushed - discarded\n");
302      fsm_Output(&ccp->fsm, CODE_RESETREQ, ccp->fsm.reqid++, NULL, 0,
303                 MB_CCPOUT);
304      m_freem(mp);
305      return NULL;
306    }
307
308    if (prefix != mip->cohnum) {
309      /*
310       * We're in stateful mode and didn't receive the expected
311       * packet.  Send a reset request, but don't tell the CCP layer
312       * about it as we don't expect to receive a Reset ACK !
313       * Guess what... M$ invented this !
314       */
315      log_Printf(LogCCP, "MPPE: Input: Got seq %u, not %u\n",
316                 prefix, mip->cohnum);
317      fsm_Output(&ccp->fsm, CODE_RESETREQ, ccp->fsm.reqid++, NULL, 0,
318                 MB_CCPOUT);
319      mip->flushrequired = 1;
320      m_freem(mp);
321      return NULL;
322    }
323
324    if ((prefix & MPPE_HEADER_FLAGMASK) == MPPE_HEADER_FLAG) {
325      log_Printf(LogDEBUG, "MPPEInput: Key changed [%u]\n", prefix);
326      MPPEKeyChange(mip);
327      dictinit = 1;
328    } else if (flushed)
329      dictinit = 1;
330
331    /*
332     * mip->cohnum contains what we expect to receive next time in stateful
333     * mode.
334     */
335    mip->cohnum++;
336    mip->cohnum &= ~MPPE_HEADER_BITMASK;
337  }
338
339  if (dictinit) {
340    log_Printf(LogDEBUG, "MPPEInput: Dictionary initialised [%u]\n", prefix);
341    RC4_set_key(&mip->rc4key, mip->keylen, mip->sesskey);
342  }
343
344  mp = mbuf_Read(mp, proto, 2);
345  RC4(&mip->rc4key, 2, (char *)proto, (char *)proto);
346  *proto = ntohs(*proto);
347
348  rp = MBUF_CTOP(mp);
349  len = m_length(mp);
350  RC4(&mip->rc4key, len, rp, rp);
351
352  log_Printf(LogDEBUG, "MPPEInput: Decrypted: Proto %02x (%d bytes)\n",
353             *proto, len);
354  log_DumpBp(LogDEBUG, "MPPEInput: Decrypted: Packet:", mp);
355
356  ccp->uncompin += len;
357
358  return mp;
359}
360
361static void
362MPPEDictSetup(void *v, struct ccp *ccp, u_short proto, struct mbuf *mi)
363{
364}
365
366static const char *
367MPPEDispOpts(struct lcp_opt *o)
368{
369  static char buf[70];
370  u_int32_t val;
371  char ch;
372  int len;
373
374  ua_ntohl(o->data, &val);
375  snprintf(buf, sizeof buf, "value 0x%08x ", (unsigned)val);
376  len = strlen(buf);
377  if (!(val & MPPE_OPT_BITMASK)) {
378    snprintf(buf + len, sizeof buf - len, "(0");
379    len++;
380  } else {
381    ch = '(';
382    if (val & MPPE_OPT_128BIT) {
383      snprintf(buf + len, sizeof buf - len, "%c128", ch);
384      len += strlen(buf + len);
385      ch = '/';
386    }
387    if (val & MPPE_OPT_56BIT) {
388      snprintf(buf + len, sizeof buf - len, "%c56", ch);
389      len += strlen(buf + len);
390      ch = '/';
391    }
392    if (val & MPPE_OPT_40BIT) {
393      snprintf(buf + len, sizeof buf - len, "%c40", ch);
394      len += strlen(buf + len);
395      ch = '/';
396    }
397  }
398
399  snprintf(buf + len, sizeof buf - len, " bits, state%s",
400           (val & MPPE_OPT_STATELESS) ? "less" : "ful");
401  len += strlen(buf + len);
402
403  if (val & MPPE_OPT_COMPRESSED) {
404    snprintf(buf + len, sizeof buf - len, ", compressed");
405    len += strlen(buf + len);
406  }
407
408  snprintf(buf + len, sizeof buf - len, ")");
409
410  return buf;
411}
412
413static int
414MPPEUsable(struct fsm *fp)
415{
416  struct lcp *lcp;
417  int ok;
418
419  lcp = &fp->link->lcp;
420  ok = (lcp->want_auth == PROTO_CHAP && lcp->want_authtype == 0x81) ||
421       (lcp->his_auth == PROTO_CHAP && lcp->his_authtype == 0x81);
422  if (!ok)
423    log_Printf(LogCCP, "MPPE: Not usable without CHAP81\n");
424
425  return ok;
426}
427
428static int
429MPPERequired(struct fsm *fp)
430{
431  return fp->link->ccp.cfg.mppe.required;
432}
433
434static u_int32_t
435MPPE_ConfigVal(const struct ccp_config *cfg)
436{
437  u_int32_t val;
438
439  val = cfg->mppe.state == MPPE_STATELESS ? MPPE_OPT_STATELESS : 0;
440  switch(cfg->mppe.keybits) {
441  case 128:
442    val |= MPPE_OPT_128BIT;
443    break;
444  case 56:
445    val |= MPPE_OPT_56BIT;
446    break;
447  case 40:
448    val |= MPPE_OPT_40BIT;
449    break;
450  case 0:
451    val |= MPPE_OPT_128BIT | MPPE_OPT_56BIT | MPPE_OPT_40BIT;
452    break;
453  }
454
455  return val;
456}
457
458/*
459 * What options should we use for our first configure request
460 */
461static void
462MPPEInitOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg)
463{
464  u_int32_t mval;
465
466  o->len = 6;
467
468  if (!MPPE_MasterKeyValid) {
469    log_Printf(LogCCP, "MPPE: MasterKey is invalid,"
470               " MPPE is available only with CHAP81 authentication\n");
471    ua_htonl(0x0, o->data);
472    return;
473  }
474
475  mval = MPPE_ConfigVal(cfg);
476  ua_htonl(&mval, o->data);
477}
478
479/*
480 * Our CCP request was NAK'd with the given options
481 */
482static int
483MPPESetOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg)
484{
485  u_int32_t mval, peer;
486
487  ua_ntohl(o->data, &peer);
488
489  if (!MPPE_MasterKeyValid)
490    /* Treat their NAK as a REJ */
491    return MODE_NAK;
492
493  mval = MPPE_ConfigVal(cfg);
494
495  /*
496   * If we haven't been configured with a specific number of keybits, allow
497   * whatever the peer asks for.
498   */
499  if (!cfg->mppe.keybits) {
500    mval &= ~MPPE_OPT_BITMASK;
501    mval |= (peer & MPPE_OPT_BITMASK);
502    if (!(mval & MPPE_OPT_BITMASK))
503      mval |= MPPE_OPT_128BIT;
504  }
505
506  /* Adjust our statelessness */
507  if (cfg->mppe.state == MPPE_ANYSTATE) {
508    mval &= ~MPPE_OPT_STATELESS;
509    mval |= (peer & MPPE_OPT_STATELESS);
510  }
511
512  ua_htonl(&mval, o->data);
513
514  return MODE_ACK;
515}
516
517/*
518 * The peer has requested the given options
519 */
520static int
521MPPESetOptsInput(struct lcp_opt *o, const struct ccp_config *cfg)
522{
523  u_int32_t mval, peer;
524  int res = MODE_ACK;
525
526  ua_ntohl(o->data, &peer);
527  if (!MPPE_MasterKeyValid) {
528    if (peer != 0) {
529      peer = 0;
530      ua_htonl(&peer, o->data);
531      return MODE_NAK;
532    } else
533      return MODE_ACK;
534  }
535
536  mval = MPPE_ConfigVal(cfg);
537
538  if (peer & ~MPPE_OPT_MASK)
539    /* He's asking for bits we don't know about */
540    res = MODE_NAK;
541
542  if (peer & MPPE_OPT_STATELESS) {
543    if (cfg->mppe.state == MPPE_STATEFUL)
544      /* Peer can't have stateless */
545      res = MODE_NAK;
546    else
547      /* Peer wants stateless, that's ok */
548      mval |= MPPE_OPT_STATELESS;
549  } else {
550    if (cfg->mppe.state == MPPE_STATELESS)
551      /* Peer must have stateless */
552      res = MODE_NAK;
553    else
554      /* Peer doesn't want stateless, that's ok */
555      mval &= ~MPPE_OPT_STATELESS;
556  }
557
558  /* If we've got a configured number of keybits - the peer must use that */
559  if (cfg->mppe.keybits) {
560    ua_htonl(&mval, o->data);
561    return peer == mval ? res : MODE_NAK;
562  }
563
564  /* If a specific number of bits hasn't been requested, we'll need to NAK */
565  switch (peer & MPPE_OPT_BITMASK) {
566  case MPPE_OPT_128BIT:
567  case MPPE_OPT_56BIT:
568  case MPPE_OPT_40BIT:
569    break;
570  default:
571    res = MODE_NAK;
572  }
573
574  /* Suggest the best number of bits */
575  mval &= ~MPPE_OPT_BITMASK;
576  if (peer & MPPE_OPT_128BIT)
577    mval |= MPPE_OPT_128BIT;
578  else if (peer & MPPE_OPT_56BIT)
579    mval |= MPPE_OPT_56BIT;
580  else if (peer & MPPE_OPT_40BIT)
581    mval |= MPPE_OPT_40BIT;
582  else
583    mval |= MPPE_OPT_128BIT;
584  ua_htonl(&mval, o->data);
585
586  return res;
587}
588
589static struct mppe_state *
590MPPE_InitState(struct lcp_opt *o)
591{
592  struct mppe_state *mp;
593  u_int32_t val;
594
595  if ((mp = calloc(1, sizeof *mp)) != NULL) {
596    ua_ntohl(o->data, &val);
597
598    switch (val & MPPE_OPT_BITMASK) {
599    case MPPE_OPT_128BIT:
600      mp->keylen = 16;
601      mp->keybits = 128;
602      break;
603    case MPPE_OPT_56BIT:
604      mp->keylen = 8;
605      mp->keybits = 56;
606      break;
607    case MPPE_OPT_40BIT:
608      mp->keylen = 8;
609      mp->keybits = 40;
610      break;
611    default:
612      log_Printf(LogWARN, "Unexpected MPPE options 0x%08x\n", val);
613      free(mp);
614      return NULL;
615    }
616
617    mp->stateless = !!(val & MPPE_OPT_STATELESS);
618  }
619
620  return mp;
621}
622
623static void *
624MPPEInitInput(struct lcp_opt *o)
625{
626  struct mppe_state *mip;
627
628  if (!MPPE_MasterKeyValid) {
629    log_Printf(LogWARN, "MPPE: Cannot initialise without CHAP81\n");
630    return NULL;
631  }
632
633  if ((mip = MPPE_InitState(o)) == NULL) {
634    log_Printf(LogWARN, "MPPEInput: Cannot initialise - unexpected options\n");
635    return NULL;
636  }
637
638  log_Printf(LogDEBUG, "MPPE: InitInput: %d-bits\n", mip->keybits);
639
640  GetAsymetricStartKey(MPPE_MasterKey, mip->mastkey, mip->keylen, 0,
641                       MPPE_IsServer);
642  GetNewKeyFromSHA(mip->mastkey, mip->mastkey, mip->keylen, mip->sesskey);
643
644  MPPEReduceSessionKey(mip);
645
646  log_Printf(LogCCP, "MPPE: Input channel initiated\n");
647
648  if (!mip->stateless) {
649    /*
650     * We need to initialise our dictionary here as the first packet we
651     * receive is unlikely to have the FLUSHED bit set.
652     */
653    log_Printf(LogDEBUG, "MPPEInitInput: Dictionary initialised [%d]\n",
654               mip->cohnum);
655    RC4_set_key(&mip->rc4key, mip->keylen, mip->sesskey);
656  } else {
657    /*
658     * We do the first key change here as the first packet is expected
659     * to have a sequence number of 0 and we'll therefore not expect
660     * to have to change the key at that point.
661     */
662    log_Printf(LogDEBUG, "MPPEInitInput: Key changed [%d]\n", mip->cohnum);
663    MPPEKeyChange(mip);
664  }
665
666  return mip;
667}
668
669static void *
670MPPEInitOutput(struct lcp_opt *o)
671{
672  struct mppe_state *mop;
673
674  if (!MPPE_MasterKeyValid) {
675    log_Printf(LogWARN, "MPPE: Cannot initialise without CHAP81\n");
676    return NULL;
677  }
678
679  if ((mop = MPPE_InitState(o)) == NULL) {
680    log_Printf(LogWARN, "MPPEOutput: Cannot initialise - unexpected options\n");
681    return NULL;
682  }
683
684  log_Printf(LogDEBUG, "MPPE: InitOutput: %d-bits\n", mop->keybits);
685
686  GetAsymetricStartKey(MPPE_MasterKey, mop->mastkey, mop->keylen, 1,
687                       MPPE_IsServer);
688  GetNewKeyFromSHA(mop->mastkey, mop->mastkey, mop->keylen, mop->sesskey);
689
690  MPPEReduceSessionKey(mop);
691
692  log_Printf(LogCCP, "MPPE: Output channel initiated\n");
693
694  if (!mop->stateless) {
695    /*
696     * We need to initialise our dictionary now as the first packet we
697     * send won't have the FLUSHED bit set.
698     */
699    log_Printf(LogDEBUG, "MPPEInitOutput: Dictionary initialised [%d]\n",
700               mop->cohnum);
701    RC4_set_key(&mop->rc4key, mop->keylen, mop->sesskey);
702  }
703
704  return mop;
705}
706
707static void
708MPPETermInput(void *v)
709{
710  free(v);
711}
712
713static void
714MPPETermOutput(void *v)
715{
716  free(v);
717}
718
719const struct ccp_algorithm MPPEAlgorithm = {
720  TY_MPPE,
721  CCP_NEG_MPPE,
722  MPPEDispOpts,
723  MPPEUsable,
724  MPPERequired,
725  {
726    MPPESetOptsInput,
727    MPPEInitInput,
728    MPPETermInput,
729    MPPEResetInput,
730    MPPEInput,
731    MPPEDictSetup
732  },
733  {
734    2,
735    MPPEInitOptsOutput,
736    MPPESetOptsOutput,
737    MPPEInitOutput,
738    MPPETermOutput,
739    MPPEResetOutput,
740    MPPEOutput
741  },
742};
743