mppe.c revision 93462
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 93462 2002-03-31 01:36:08Z brian $
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, n;
373
374  ua_ntohl(o->data, &val);
375  len = 0;
376  if ((n = snprintf(buf, sizeof buf, "value 0x%08x ", (unsigned)val)) > 0)
377    len += n;
378  if (!(val & MPPE_OPT_BITMASK)) {
379    if ((n = snprintf(buf + len, sizeof buf - len, "(0")) > 0)
380      len += n;
381  } else {
382    ch = '(';
383    if (val & MPPE_OPT_128BIT) {
384      if ((n = snprintf(buf + len, sizeof buf - len, "%c128", ch)) > 0)
385        len += n;
386      ch = '/';
387    }
388    if (val & MPPE_OPT_56BIT) {
389      if ((n = snprintf(buf + len, sizeof buf - len, "%c56", ch)) > 0)
390        len += n;
391      ch = '/';
392    }
393    if (val & MPPE_OPT_40BIT) {
394      if ((n = snprintf(buf + len, sizeof buf - len, "%c40", ch)) > 0)
395        len += n;
396      ch = '/';
397    }
398  }
399
400  if ((n = snprintf(buf + len, sizeof buf - len, " bits, state%s",
401                    (val & MPPE_OPT_STATELESS) ? "less" : "ful")) > 0)
402    len += n;
403
404  if (val & MPPE_OPT_COMPRESSED) {
405    if ((n = snprintf(buf + len, sizeof buf - len, ", compressed")) > 0)
406      len += n;
407  }
408
409  snprintf(buf + len, sizeof buf - len, ")");
410
411  return buf;
412}
413
414static int
415MPPEUsable(struct fsm *fp)
416{
417  struct lcp *lcp;
418  int ok;
419
420  lcp = &fp->link->lcp;
421  ok = (lcp->want_auth == PROTO_CHAP && lcp->want_authtype == 0x81) ||
422       (lcp->his_auth == PROTO_CHAP && lcp->his_authtype == 0x81);
423  if (!ok)
424    log_Printf(LogCCP, "MPPE: Not usable without CHAP81\n");
425
426  return ok;
427}
428
429static int
430MPPERequired(struct fsm *fp)
431{
432  return fp->link->ccp.cfg.mppe.required;
433}
434
435static u_int32_t
436MPPE_ConfigVal(const struct ccp_config *cfg)
437{
438  u_int32_t val;
439
440  val = cfg->mppe.state == MPPE_STATELESS ? MPPE_OPT_STATELESS : 0;
441  switch(cfg->mppe.keybits) {
442  case 128:
443    val |= MPPE_OPT_128BIT;
444    break;
445  case 56:
446    val |= MPPE_OPT_56BIT;
447    break;
448  case 40:
449    val |= MPPE_OPT_40BIT;
450    break;
451  case 0:
452    val |= MPPE_OPT_128BIT | MPPE_OPT_56BIT | MPPE_OPT_40BIT;
453    break;
454  }
455
456  return val;
457}
458
459/*
460 * What options should we use for our first configure request
461 */
462static void
463MPPEInitOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg)
464{
465  u_int32_t mval;
466
467  o->len = 6;
468
469  if (!MPPE_MasterKeyValid) {
470    log_Printf(LogCCP, "MPPE: MasterKey is invalid,"
471               " MPPE is available only with CHAP81 authentication\n");
472    ua_htonl(0x0, o->data);
473    return;
474  }
475
476  mval = MPPE_ConfigVal(cfg);
477  ua_htonl(&mval, o->data);
478}
479
480/*
481 * Our CCP request was NAK'd with the given options
482 */
483static int
484MPPESetOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg)
485{
486  u_int32_t mval, peer;
487
488  ua_ntohl(o->data, &peer);
489
490  if (!MPPE_MasterKeyValid)
491    /* Treat their NAK as a REJ */
492    return MODE_NAK;
493
494  mval = MPPE_ConfigVal(cfg);
495
496  /*
497   * If we haven't been configured with a specific number of keybits, allow
498   * whatever the peer asks for.
499   */
500  if (!cfg->mppe.keybits) {
501    mval &= ~MPPE_OPT_BITMASK;
502    mval |= (peer & MPPE_OPT_BITMASK);
503    if (!(mval & MPPE_OPT_BITMASK))
504      mval |= MPPE_OPT_128BIT;
505  }
506
507  /* Adjust our statelessness */
508  if (cfg->mppe.state == MPPE_ANYSTATE) {
509    mval &= ~MPPE_OPT_STATELESS;
510    mval |= (peer & MPPE_OPT_STATELESS);
511  }
512
513  ua_htonl(&mval, o->data);
514
515  return MODE_ACK;
516}
517
518/*
519 * The peer has requested the given options
520 */
521static int
522MPPESetOptsInput(struct lcp_opt *o, const struct ccp_config *cfg)
523{
524  u_int32_t mval, peer;
525  int res = MODE_ACK;
526
527  ua_ntohl(o->data, &peer);
528  if (!MPPE_MasterKeyValid) {
529    if (peer != 0) {
530      peer = 0;
531      ua_htonl(&peer, o->data);
532      return MODE_NAK;
533    } else
534      return MODE_ACK;
535  }
536
537  mval = MPPE_ConfigVal(cfg);
538
539  if (peer & ~MPPE_OPT_MASK)
540    /* He's asking for bits we don't know about */
541    res = MODE_NAK;
542
543  if (peer & MPPE_OPT_STATELESS) {
544    if (cfg->mppe.state == MPPE_STATEFUL)
545      /* Peer can't have stateless */
546      res = MODE_NAK;
547    else
548      /* Peer wants stateless, that's ok */
549      mval |= MPPE_OPT_STATELESS;
550  } else {
551    if (cfg->mppe.state == MPPE_STATELESS)
552      /* Peer must have stateless */
553      res = MODE_NAK;
554    else
555      /* Peer doesn't want stateless, that's ok */
556      mval &= ~MPPE_OPT_STATELESS;
557  }
558
559  /* If we've got a configured number of keybits - the peer must use that */
560  if (cfg->mppe.keybits) {
561    ua_htonl(&mval, o->data);
562    return peer == mval ? res : MODE_NAK;
563  }
564
565  /* If a specific number of bits hasn't been requested, we'll need to NAK */
566  switch (peer & MPPE_OPT_BITMASK) {
567  case MPPE_OPT_128BIT:
568  case MPPE_OPT_56BIT:
569  case MPPE_OPT_40BIT:
570    break;
571  default:
572    res = MODE_NAK;
573  }
574
575  /* Suggest the best number of bits */
576  mval &= ~MPPE_OPT_BITMASK;
577  if (peer & MPPE_OPT_128BIT)
578    mval |= MPPE_OPT_128BIT;
579  else if (peer & MPPE_OPT_56BIT)
580    mval |= MPPE_OPT_56BIT;
581  else if (peer & MPPE_OPT_40BIT)
582    mval |= MPPE_OPT_40BIT;
583  else
584    mval |= MPPE_OPT_128BIT;
585  ua_htonl(&mval, o->data);
586
587  return res;
588}
589
590static struct mppe_state *
591MPPE_InitState(struct lcp_opt *o)
592{
593  struct mppe_state *mp;
594  u_int32_t val;
595
596  if ((mp = calloc(1, sizeof *mp)) != NULL) {
597    ua_ntohl(o->data, &val);
598
599    switch (val & MPPE_OPT_BITMASK) {
600    case MPPE_OPT_128BIT:
601      mp->keylen = 16;
602      mp->keybits = 128;
603      break;
604    case MPPE_OPT_56BIT:
605      mp->keylen = 8;
606      mp->keybits = 56;
607      break;
608    case MPPE_OPT_40BIT:
609      mp->keylen = 8;
610      mp->keybits = 40;
611      break;
612    default:
613      log_Printf(LogWARN, "Unexpected MPPE options 0x%08x\n", val);
614      free(mp);
615      return NULL;
616    }
617
618    mp->stateless = !!(val & MPPE_OPT_STATELESS);
619  }
620
621  return mp;
622}
623
624static void *
625MPPEInitInput(struct lcp_opt *o)
626{
627  struct mppe_state *mip;
628
629  if (!MPPE_MasterKeyValid) {
630    log_Printf(LogWARN, "MPPE: Cannot initialise without CHAP81\n");
631    return NULL;
632  }
633
634  if ((mip = MPPE_InitState(o)) == NULL) {
635    log_Printf(LogWARN, "MPPEInput: Cannot initialise - unexpected options\n");
636    return NULL;
637  }
638
639  log_Printf(LogDEBUG, "MPPE: InitInput: %d-bits\n", mip->keybits);
640
641  GetAsymetricStartKey(MPPE_MasterKey, mip->mastkey, mip->keylen, 0,
642                       MPPE_IsServer);
643  GetNewKeyFromSHA(mip->mastkey, mip->mastkey, mip->keylen, mip->sesskey);
644
645  MPPEReduceSessionKey(mip);
646
647  log_Printf(LogCCP, "MPPE: Input channel initiated\n");
648
649  if (!mip->stateless) {
650    /*
651     * We need to initialise our dictionary here as the first packet we
652     * receive is unlikely to have the FLUSHED bit set.
653     */
654    log_Printf(LogDEBUG, "MPPEInitInput: Dictionary initialised [%d]\n",
655               mip->cohnum);
656    RC4_set_key(&mip->rc4key, mip->keylen, mip->sesskey);
657  } else {
658    /*
659     * We do the first key change here as the first packet is expected
660     * to have a sequence number of 0 and we'll therefore not expect
661     * to have to change the key at that point.
662     */
663    log_Printf(LogDEBUG, "MPPEInitInput: Key changed [%d]\n", mip->cohnum);
664    MPPEKeyChange(mip);
665  }
666
667  return mip;
668}
669
670static void *
671MPPEInitOutput(struct lcp_opt *o)
672{
673  struct mppe_state *mop;
674
675  if (!MPPE_MasterKeyValid) {
676    log_Printf(LogWARN, "MPPE: Cannot initialise without CHAP81\n");
677    return NULL;
678  }
679
680  if ((mop = MPPE_InitState(o)) == NULL) {
681    log_Printf(LogWARN, "MPPEOutput: Cannot initialise - unexpected options\n");
682    return NULL;
683  }
684
685  log_Printf(LogDEBUG, "MPPE: InitOutput: %d-bits\n", mop->keybits);
686
687  GetAsymetricStartKey(MPPE_MasterKey, mop->mastkey, mop->keylen, 1,
688                       MPPE_IsServer);
689  GetNewKeyFromSHA(mop->mastkey, mop->mastkey, mop->keylen, mop->sesskey);
690
691  MPPEReduceSessionKey(mop);
692
693  log_Printf(LogCCP, "MPPE: Output channel initiated\n");
694
695  if (!mop->stateless) {
696    /*
697     * We need to initialise our dictionary now as the first packet we
698     * send won't have the FLUSHED bit set.
699     */
700    log_Printf(LogDEBUG, "MPPEInitOutput: Dictionary initialised [%d]\n",
701               mop->cohnum);
702    RC4_set_key(&mop->rc4key, mop->keylen, mop->sesskey);
703  }
704
705  return mop;
706}
707
708static void
709MPPETermInput(void *v)
710{
711  free(v);
712}
713
714static void
715MPPETermOutput(void *v)
716{
717  free(v);
718}
719
720const struct ccp_algorithm MPPEAlgorithm = {
721  TY_MPPE,
722  CCP_NEG_MPPE,
723  MPPEDispOpts,
724  MPPEUsable,
725  MPPERequired,
726  {
727    MPPESetOptsInput,
728    MPPEInitInput,
729    MPPETermInput,
730    MPPEResetInput,
731    MPPEInput,
732    MPPEDictSetup
733  },
734  {
735    2,
736    MPPEInitOptsOutput,
737    MPPESetOptsOutput,
738    MPPEInitOutput,
739    MPPETermOutput,
740    MPPEResetOutput,
741    MPPEOutput
742  },
743};
744