mppe.c revision 79165
167910Sbrian/*-
267910Sbrian * Copyright (c) 2000 Semen Ustimenko <semenu@FreeBSD.org>
367910Sbrian * All rights reserved.
467910Sbrian *
567910Sbrian * Redistribution and use in source and binary forms, with or without
667910Sbrian * modification, are permitted provided that the following conditions
767910Sbrian * are met:
867910Sbrian * 1. Redistributions of source code must retain the above copyright
967910Sbrian *    notice, this list of conditions and the following disclaimer.
1067910Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1167910Sbrian *    notice, this list of conditions and the following disclaimer in the
1267910Sbrian *    documentation and/or other materials provided with the distribution.
1367910Sbrian *
1467910Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1567910Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1667910Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1767910Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1867910Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1967910Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2067910Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2167910Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2267910Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2367910Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2467910Sbrian * SUCH DAMAGE.
2567910Sbrian *
2667910Sbrian * $FreeBSD: head/usr.sbin/ppp/mppe.c 79165 2001-07-03 22:20:19Z brian $
2767910Sbrian */
2867910Sbrian
2967910Sbrian#include <sys/types.h>
3067910Sbrian
3167910Sbrian#include <stdio.h>
3267910Sbrian#include <stdlib.h>
3378411Sbrian#include <string.h>
3467910Sbrian#include <termios.h>
3568344Sbrian#ifdef __FreeBSD__
3667910Sbrian#include <sha.h>
3768344Sbrian#else
3868344Sbrian#include <openssl/sha.h>
3968344Sbrian#endif
4067910Sbrian#include <openssl/rc4.h>
4167910Sbrian
4267910Sbrian#include "defs.h"
4367910Sbrian#include "mbuf.h"
4467910Sbrian#include "log.h"
4567910Sbrian#include "timer.h"
4667910Sbrian#include "fsm.h"
4767910Sbrian#include "lqr.h"
4867910Sbrian#include "hdlc.h"
4967910Sbrian#include "lcp.h"
5067910Sbrian#include "ccp.h"
5172025Sbrian#include "throughput.h"
5272025Sbrian#include "layer.h"
5372025Sbrian#include "link.h"
5467910Sbrian#include "chap_ms.h"
5572025Sbrian#include "proto.h"
5667910Sbrian#include "mppe.h"
5767910Sbrian
5867910Sbrian/*
5967910Sbrian * Documentation:
6067910Sbrian *
6167910Sbrian * draft-ietf-pppext-mppe-04.txt
6267910Sbrian * draft-ietf-pppext-mppe-keys-02.txt
6367910Sbrian */
6467910Sbrian
6578411Sbrian#define	MPPE_OPT_STATELESS	0x1000000
6678411Sbrian#define	MPPE_OPT_COMPRESSED	0x01
6778411Sbrian#define	MPPE_OPT_40BIT		0x20
6878411Sbrian#define	MPPE_OPT_56BIT		0x80
6978411Sbrian#define	MPPE_OPT_128BIT		0x40
7078411Sbrian#define	MPPE_OPT_BITMASK	0xe0
7178411Sbrian#define	MPPE_OPT_MASK		(MPPE_OPT_STATELESS | MPPE_OPT_BITMASK)
7278411Sbrian
7378411Sbrian#define	MPPE_FLUSHED		0x8000
7478411Sbrian#define	MPPE_ENCRYPTED		0x1000
7578411Sbrian#define	MPPE_HEADER_BITMASK	0xf000
7678411Sbrian#define	MPPE_HEADER_FLAG	0x00ff
7778411Sbrian#define	MPPE_HEADER_FLAGMASK	0x00ff
7878411Sbrian#define	MPPE_HEADER_FLAGSHIFT	8
7978411Sbrian
8067910Sbrianstruct mppe_state {
8178411Sbrian  unsigned	stateless : 1;
8278411Sbrian  unsigned	flushnext : 1;
8378411Sbrian  unsigned	flushrequired : 1;
8478411Sbrian  int		cohnum;
8578411Sbrian  int		keylen;			/* 8 or 16 bytes */
8678411Sbrian  int 		keybits;		/* 40, 56 or 128 bits */
8778411Sbrian  char		sesskey[MPPE_KEY_LEN];
8878411Sbrian  char		mastkey[MPPE_KEY_LEN];
8978411Sbrian  RC4_KEY	rc4key;
9067910Sbrian};
9167910Sbrian
9267910Sbrianint MPPE_MasterKeyValid = 0;
9368461Sbrianint MPPE_IsServer = 0;
9467910Sbrianchar MPPE_MasterKey[MPPE_KEY_LEN];
9567910Sbrian
9678411Sbrian/*
9778411Sbrian * The peer has missed a packet.  Mark the next output frame to be FLUSHED
9878411Sbrian */
9978411Sbrianstatic int
10067910SbrianMPPEResetOutput(void *v)
10167910Sbrian{
10278411Sbrian  struct mppe_state *mop = (struct mppe_state *)v;
10378411Sbrian
10478411Sbrian  if (mop->stateless)
10578411Sbrian    log_Printf(LogCCP, "MPPE: Unexpected output channel reset\n");
10678411Sbrian  else {
10778411Sbrian    log_Printf(LogCCP, "MPPE: Output channel reset\n");
10878411Sbrian    mop->flushnext = 1;
10978411Sbrian  }
11078411Sbrian
11178411Sbrian  return 0;		/* Ask FSM not to ACK */
11267910Sbrian}
11367910Sbrian
11467912Sbrianstatic void
11567912SbrianMPPEReduceSessionKey(struct mppe_state *mp)
11667912Sbrian{
11767910Sbrian  switch(mp->keybits) {
11867910Sbrian  case 40:
11967910Sbrian    mp->sesskey[2] = 0x9e;
12067910Sbrian    mp->sesskey[1] = 0x26;
12167910Sbrian  case 56:
12267910Sbrian    mp->sesskey[0] = 0xd1;
12367910Sbrian  case 128:
12467910Sbrian  }
12567910Sbrian}
12667910Sbrian
12767912Sbrianstatic void
12867912SbrianMPPEKeyChange(struct mppe_state *mp)
12967912Sbrian{
13067910Sbrian  char InterimKey[MPPE_KEY_LEN];
13167910Sbrian  RC4_KEY RC4Key;
13267910Sbrian
13367910Sbrian  GetNewKeyFromSHA(mp->mastkey, mp->sesskey, mp->keylen, InterimKey);
13467910Sbrian  RC4_set_key(&RC4Key, mp->keylen, InterimKey);
13567910Sbrian  RC4(&RC4Key, mp->keylen, InterimKey, mp->sesskey);
13667910Sbrian
13767910Sbrian  MPPEReduceSessionKey(mp);
13867910Sbrian}
13967910Sbrian
14067910Sbrianstatic struct mbuf *
14167910SbrianMPPEOutput(void *v, struct ccp *ccp, struct link *l, int pri, u_short *proto,
14267910Sbrian           struct mbuf *mp)
14367910Sbrian{
14467910Sbrian  struct mppe_state *mop = (struct mppe_state *)v;
14567910Sbrian  struct mbuf *mo;
14678411Sbrian  u_short nproto, prefix;
14778411Sbrian  int dictinit, ilen, len;
14867910Sbrian  char *rp;
14967910Sbrian
15067910Sbrian  ilen = m_length(mp);
15178411Sbrian  dictinit = 0;
15267910Sbrian
15367910Sbrian  log_Printf(LogDEBUG, "MPPE: Output: Proto %02x (%d bytes)\n", *proto, ilen);
15467910Sbrian  if (*proto < 0x21 && *proto > 0xFA) {
15567910Sbrian    log_Printf(LogDEBUG, "MPPE: Output: Not encrypting\n");
15678411Sbrian    ccp->compout += ilen;
15778411Sbrian    ccp->uncompout += ilen;
15867910Sbrian    return mp;
15967910Sbrian  }
16067910Sbrian
16167910Sbrian  log_DumpBp(LogDEBUG, "MPPE: Output: Encrypt packet:", mp);
16267910Sbrian
16367910Sbrian  /* Get mbuf for prefixes */
16467910Sbrian  mo = m_get(4, MB_CCPOUT);
16567910Sbrian  mo->m_next = mp;
16667910Sbrian
16778411Sbrian  rp = MBUF_CTOP(mo);
16878411Sbrian  prefix = MPPE_ENCRYPTED | mop->cohnum;
16967910Sbrian
17078411Sbrian  if (mop->stateless ||
17178411Sbrian      (mop->cohnum & MPPE_HEADER_FLAGMASK) == MPPE_HEADER_FLAG) {
17278411Sbrian    /* Change our key */
17378411Sbrian    log_Printf(LogDEBUG, "MPPEOutput: Key changed [%d]\n", mop->cohnum);
17478411Sbrian    MPPEKeyChange(mop);
17578411Sbrian    dictinit = 1;
17678411Sbrian  }
17778411Sbrian
17878411Sbrian  if (mop->stateless || mop->flushnext) {
17978411Sbrian    prefix |= MPPE_FLUSHED;
18078411Sbrian    dictinit = 1;
18178411Sbrian    mop->flushnext = 0;
18278411Sbrian  }
18378411Sbrian
18478411Sbrian  if (dictinit) {
18578411Sbrian    /* Initialise our dictionary */
18678411Sbrian    log_Printf(LogDEBUG, "MPPEOutput: Dictionary initialised [%d]\n",
18778411Sbrian               mop->cohnum);
18878411Sbrian    RC4_set_key(&mop->rc4key, mop->keylen, mop->sesskey);
18978411Sbrian  }
19078411Sbrian
19167910Sbrian  /* Set MPPE packet prefix */
19278411Sbrian  *(u_short *)rp = htons(prefix);
19367910Sbrian
19467910Sbrian  /* Save encrypted protocol number */
19567910Sbrian  nproto = htons(*proto);
19667910Sbrian  RC4(&mop->rc4key, 2, (char *)&nproto, rp + 2);
19767910Sbrian
19867910Sbrian  /* Encrypt main packet */
19967910Sbrian  rp = MBUF_CTOP(mp);
20067910Sbrian  RC4(&mop->rc4key, ilen, rp, rp);
20167910Sbrian
20278411Sbrian  mop->cohnum++;
20378411Sbrian  mop->cohnum &= ~MPPE_HEADER_BITMASK;
20467910Sbrian
20578411Sbrian  /* Set the protocol number */
20667910Sbrian  *proto = ccp_Proto(ccp);
20778411Sbrian  len = m_length(mo);
20878411Sbrian  ccp->uncompout += ilen;
20978411Sbrian  ccp->compout += len;
21067910Sbrian
21167912Sbrian  log_Printf(LogDEBUG, "MPPE: Output: Encrypted: Proto %02x (%d bytes)\n",
21278411Sbrian             *proto, len);
21367910Sbrian
21467910Sbrian  return mo;
21567910Sbrian}
21667910Sbrian
21767910Sbrianstatic void
21867910SbrianMPPEResetInput(void *v)
21967910Sbrian{
22078411Sbrian  log_Printf(LogCCP, "MPPE: Unexpected input channel ack\n");
22167910Sbrian}
22267910Sbrian
22367910Sbrianstatic struct mbuf *
22467910SbrianMPPEInput(void *v, struct ccp *ccp, u_short *proto, struct mbuf *mp)
22567910Sbrian{
22667910Sbrian  struct mppe_state *mip = (struct mppe_state *)v;
22767910Sbrian  u_short prefix;
22867910Sbrian  char *rp;
22978411Sbrian  int dictinit, flushed, ilen, len, n;
23067910Sbrian
23167910Sbrian  ilen = m_length(mp);
23278411Sbrian  dictinit = 0;
23378411Sbrian  ccp->compin += ilen;
23467910Sbrian
23567910Sbrian  log_Printf(LogDEBUG, "MPPE: Input: Proto %02x (%d bytes)\n", *proto, ilen);
23667910Sbrian  log_DumpBp(LogDEBUG, "MPPE: Input: Packet:", mp);
23767910Sbrian
23867910Sbrian  mp = mbuf_Read(mp, &prefix, 2);
23967910Sbrian  prefix = ntohs(prefix);
24078411Sbrian  flushed = prefix & MPPE_FLUSHED;
24178411Sbrian  prefix &= ~flushed;
24278411Sbrian  if ((prefix & MPPE_HEADER_BITMASK) != MPPE_ENCRYPTED) {
24378411Sbrian    log_Printf(LogERROR, "MPPE: Input: Invalid packet (flags = 0x%x)\n",
24478411Sbrian               (prefix & MPPE_HEADER_BITMASK) | flushed);
24567910Sbrian    m_freem(mp);
24667910Sbrian    return NULL;
24767910Sbrian  }
24867910Sbrian
24978411Sbrian  prefix &= ~MPPE_HEADER_BITMASK;
25078411Sbrian
25178411Sbrian  if (!flushed && mip->stateless) {
25278411Sbrian    log_Printf(LogCCP, "MPPEInput: Packet without MPPE_FLUSHED set"
25378411Sbrian               " in stateless mode\n");
25478411Sbrian    flushed = MPPE_FLUSHED;
25578411Sbrian    /* Should we really continue ? */
25667910Sbrian  }
25767910Sbrian
25878411Sbrian  if (mip->stateless) {
25978411Sbrian    /* Change our key for each missed packet in stateless mode */
26078411Sbrian    while (prefix != mip->cohnum) {
26178411Sbrian      log_Printf(LogDEBUG, "MPPEInput: Key changed [%u]\n", prefix);
26278411Sbrian      MPPEKeyChange(mip);
26378411Sbrian      /*
26478411Sbrian       * mip->cohnum contains what we received last time in stateless
26578411Sbrian       * mode.
26678411Sbrian       */
26778411Sbrian      mip->cohnum++;
26878411Sbrian      mip->cohnum &= ~MPPE_HEADER_BITMASK;
26978411Sbrian    }
27078411Sbrian    dictinit = 1;
27178411Sbrian  } else {
27278411Sbrian    if (flushed) {
27378411Sbrian      /*
27478411Sbrian       * We can always process a flushed packet.
27578411Sbrian       * Catch up on any outstanding key changes.
27678411Sbrian       */
27778411Sbrian      n = (prefix >> MPPE_HEADER_FLAGSHIFT) -
27878411Sbrian          (mip->cohnum >> MPPE_HEADER_FLAGSHIFT);
27978411Sbrian      while (n--) {
28078411Sbrian        log_Printf(LogDEBUG, "MPPEInput: Key changed during catchup [%u]\n",
28178411Sbrian                   prefix);
28278411Sbrian        MPPEKeyChange(mip);
28378411Sbrian      }
28478411Sbrian      mip->flushrequired = 0;
28578411Sbrian      mip->cohnum = prefix;
28678411Sbrian      dictinit = 1;
28778411Sbrian    }
28867910Sbrian
28978411Sbrian    if (mip->flushrequired) {
29078411Sbrian      /*
29178411Sbrian       * Perhaps we should be lenient if
29278411Sbrian       * (prefix & MPPE_HEADER_FLAGMASK) == MPPE_HEADER_FLAG
29378411Sbrian       * The spec says that we shouldn't be though....
29478411Sbrian       */
29578411Sbrian      log_Printf(LogDEBUG, "MPPE: Not flushed - discarded\n");
29678411Sbrian      m_freem(mp);
29778411Sbrian      return NULL;
29878411Sbrian    }
29978411Sbrian
30078411Sbrian    if (prefix != mip->cohnum) {
30178411Sbrian      /*
30278411Sbrian       * We're in stateful mode and didn't receive the expected
30378411Sbrian       * packet.  Send a reset request, but don't tell the CCP layer
30478411Sbrian       * about it as we don't expect to receive a Reset ACK !
30578411Sbrian       * Guess what... M$ invented this !
30678411Sbrian       */
30778411Sbrian      log_Printf(LogCCP, "MPPE: Input: Got seq %u, not %u\n",
30878411Sbrian                 prefix, mip->cohnum);
30978411Sbrian      fsm_Output(&ccp->fsm, CODE_RESETREQ, ccp->fsm.reqid++, NULL, 0,
31078411Sbrian                 MB_CCPOUT);
31178411Sbrian      mip->flushrequired = 1;
31278411Sbrian      m_freem(mp);
31378411Sbrian      return NULL;
31478411Sbrian    }
31578411Sbrian
31678411Sbrian    if ((prefix & MPPE_HEADER_FLAGMASK) == MPPE_HEADER_FLAG) {
31778411Sbrian      log_Printf(LogDEBUG, "MPPEInput: Key changed [%u]\n", prefix);
31878411Sbrian      MPPEKeyChange(mip);
31978411Sbrian      dictinit = 1;
32078411Sbrian    } else if (flushed)
32178411Sbrian      dictinit = 1;
32278411Sbrian
32378411Sbrian    /*
32478411Sbrian     * mip->cohnum contains what we expect to receive next time in stateful
32578411Sbrian     * mode.
32678411Sbrian     */
32778411Sbrian    mip->cohnum++;
32878411Sbrian    mip->cohnum &= ~MPPE_HEADER_BITMASK;
32978411Sbrian  }
33078411Sbrian
33178411Sbrian  if (dictinit) {
33278411Sbrian    log_Printf(LogDEBUG, "MPPEInput: Dictionary initialised [%u]\n", prefix);
33378411Sbrian    RC4_set_key(&mip->rc4key, mip->keylen, mip->sesskey);
33478411Sbrian  }
33578411Sbrian
33667910Sbrian  mp = mbuf_Read(mp, proto, 2);
33767910Sbrian  RC4(&mip->rc4key, 2, (char *)proto, (char *)proto);
33867910Sbrian  *proto = ntohs(*proto);
33967910Sbrian
34067910Sbrian  rp = MBUF_CTOP(mp);
34178411Sbrian  len = m_length(mp);
34278411Sbrian  RC4(&mip->rc4key, len, rp, rp);
34367910Sbrian
34478411Sbrian  log_Printf(LogDEBUG, "MPPEInput: Decrypted: Proto %02x (%d bytes)\n",
34578411Sbrian             *proto, len);
34678411Sbrian  log_DumpBp(LogDEBUG, "MPPEInput: Decrypted: Packet:", mp);
34767910Sbrian
34878411Sbrian  ccp->uncompin += len;
34967910Sbrian
35067910Sbrian  return mp;
35167910Sbrian}
35267910Sbrian
35367910Sbrianstatic void
35467910SbrianMPPEDictSetup(void *v, struct ccp *ccp, u_short proto, struct mbuf *mi)
35567910Sbrian{
35667910Sbrian}
35767910Sbrian
35867910Sbrianstatic const char *
35967910SbrianMPPEDispOpts(struct lcp_opt *o)
36067910Sbrian{
36178411Sbrian  static char buf[70];
36278411Sbrian  u_int32_t val = ntohl(*(u_int32_t *)o->data);
36378411Sbrian  char ch;
36478411Sbrian  int len;
36578411Sbrian
36678411Sbrian  snprintf(buf, sizeof buf, "value 0x%08x ", (unsigned)val);
36778411Sbrian  len = strlen(buf);
36878411Sbrian  if (!(val & MPPE_OPT_BITMASK)) {
36978411Sbrian    snprintf(buf + len, sizeof buf - len, "(0");
37078411Sbrian    len++;
37178411Sbrian  } else {
37278411Sbrian    ch = '(';
37378411Sbrian    if (val & MPPE_OPT_128BIT) {
37478411Sbrian      snprintf(buf + len, sizeof buf - len, "%c128", ch);
37578411Sbrian      len += strlen(buf + len);
37678411Sbrian      ch = '/';
37778411Sbrian    }
37878411Sbrian    if (val & MPPE_OPT_56BIT) {
37978411Sbrian      snprintf(buf + len, sizeof buf - len, "%c56", ch);
38078411Sbrian      len += strlen(buf + len);
38178411Sbrian      ch = '/';
38278411Sbrian    }
38378411Sbrian    if (val & MPPE_OPT_40BIT) {
38478411Sbrian      snprintf(buf + len, sizeof buf - len, "%c40", ch);
38578411Sbrian      len += strlen(buf + len);
38678411Sbrian      ch = '/';
38778411Sbrian    }
38878411Sbrian  }
38978411Sbrian
39078411Sbrian  snprintf(buf + len, sizeof buf - len, " bits, state%s",
39178411Sbrian           (val & MPPE_OPT_STATELESS) ? "less" : "full");
39278411Sbrian  len += strlen(buf + len);
39378411Sbrian
39478411Sbrian  if (val & MPPE_OPT_COMPRESSED) {
39578411Sbrian    snprintf(buf + len, sizeof buf - len, ", compressed");
39678411Sbrian    len += strlen(buf + len);
39778411Sbrian  }
39878411Sbrian
39978411Sbrian  snprintf(buf + len, sizeof buf - len, ")");
40078411Sbrian
40167910Sbrian  return buf;
40267910Sbrian}
40367910Sbrian
40472025Sbrianstatic int
40572025SbrianMPPEUsable(struct fsm *fp)
40672025Sbrian{
40772025Sbrian  struct lcp *lcp;
40872025Sbrian  int ok;
40972025Sbrian
41072025Sbrian  lcp = &fp->link->lcp;
41172025Sbrian  ok = (lcp->want_auth == PROTO_CHAP && lcp->want_authtype == 0x81) ||
41272025Sbrian       (lcp->his_auth == PROTO_CHAP && lcp->his_authtype == 0x81);
41372025Sbrian  if (!ok)
41472025Sbrian    log_Printf(LogCCP, "MPPE: Not usable without CHAP81\n");
41572025Sbrian
41672025Sbrian  return ok;
41772025Sbrian}
41872025Sbrian
41978411Sbrianstatic int
42078411SbrianMPPERequired(struct fsm *fp)
42178411Sbrian{
42278411Sbrian  return fp->link->ccp.cfg.mppe.required;
42378411Sbrian}
42478411Sbrian
42578411Sbrianstatic u_int32_t
42678411SbrianMPPE_ConfigVal(const struct ccp_config *cfg)
42778411Sbrian{
42878411Sbrian  u_int32_t val;
42978411Sbrian
43078411Sbrian  val = cfg->mppe.state == MPPE_STATELESS ? MPPE_OPT_STATELESS : 0;
43178411Sbrian  switch(cfg->mppe.keybits) {
43278411Sbrian  case 128:
43378411Sbrian    val |= MPPE_OPT_128BIT;
43478411Sbrian    break;
43578411Sbrian  case 56:
43678411Sbrian    val |= MPPE_OPT_56BIT;
43778411Sbrian    break;
43878411Sbrian  case 40:
43978411Sbrian    val |= MPPE_OPT_40BIT;
44078411Sbrian    break;
44178411Sbrian  case 0:
44278411Sbrian    val |= MPPE_OPT_128BIT | MPPE_OPT_56BIT | MPPE_OPT_40BIT;
44378411Sbrian    break;
44478411Sbrian  }
44578411Sbrian
44678411Sbrian  return val;
44778411Sbrian}
44878411Sbrian
44978411Sbrian/*
45078411Sbrian * What options should we use for our first configure request
45178411Sbrian */
45267910Sbrianstatic void
45367910SbrianMPPEInitOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg)
45467910Sbrian{
45578411Sbrian  u_int32_t *p = (u_int32_t *)o->data;
45667910Sbrian
45767910Sbrian  o->len = 6;
45867910Sbrian
45967910Sbrian  if (!MPPE_MasterKeyValid) {
46070498Sbrian    log_Printf(LogCCP, "MPPE: MasterKey is invalid,"
46171971Sbrian               " MPPE is available only with CHAP81 authentication\n");
46278411Sbrian    *p = htonl(0x0);
46367910Sbrian    return;
46467910Sbrian  }
46567910Sbrian
46678411Sbrian  *p = htonl(MPPE_ConfigVal(cfg));
46767910Sbrian}
46867910Sbrian
46978411Sbrian/*
47078411Sbrian * Our CCP request was NAK'd with the given options
47178411Sbrian */
47267910Sbrianstatic int
47378411SbrianMPPESetOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg)
47467910Sbrian{
47578411Sbrian  u_int32_t *p = (u_int32_t *)o->data;
47678411Sbrian  u_int32_t peer = ntohl(*p);
47778411Sbrian  u_int32_t mval;
47867910Sbrian
47978411Sbrian  if (!MPPE_MasterKeyValid)
48078411Sbrian    /* Treat their NAK as a REJ */
48178411Sbrian    return MODE_NAK;
48267910Sbrian
48378411Sbrian  mval = MPPE_ConfigVal(cfg);
48478411Sbrian
48578411Sbrian  /*
48678411Sbrian   * If we haven't been configured with a specific number of keybits, allow
48778411Sbrian   * whatever the peer asks for.
48878411Sbrian   */
48978411Sbrian  if (!cfg->mppe.keybits) {
49078411Sbrian    mval &= ~MPPE_OPT_BITMASK;
49178411Sbrian    mval |= (peer & MPPE_OPT_BITMASK);
49278411Sbrian    if (!(mval & MPPE_OPT_BITMASK))
49378411Sbrian      mval |= MPPE_OPT_128BIT;
49467910Sbrian  }
49567910Sbrian
49678411Sbrian  /* Adjust our statelessness */
49778411Sbrian  if (cfg->mppe.state == MPPE_ANYSTATE) {
49878411Sbrian    mval &= ~MPPE_OPT_STATELESS;
49978411Sbrian    mval |= (peer & MPPE_OPT_STATELESS);
50078411Sbrian  }
50167910Sbrian
50278411Sbrian  *p = htonl(mval);
50378411Sbrian
50478411Sbrian  return MODE_ACK;
50567910Sbrian}
50667910Sbrian
50778411Sbrian/*
50878411Sbrian * The peer has requested the given options
50978411Sbrian */
51067910Sbrianstatic int
51167910SbrianMPPESetOptsInput(struct lcp_opt *o, const struct ccp_config *cfg)
51267910Sbrian{
51378411Sbrian  u_int32_t *p = (u_int32_t *)(o->data);
51478411Sbrian  u_int32_t peer = ntohl(*p);
51578411Sbrian  u_int32_t mval;
51678411Sbrian  int res = MODE_ACK;
51767910Sbrian
51867910Sbrian  if (!MPPE_MasterKeyValid) {
51967910Sbrian    if (*p != 0x0) {
52067910Sbrian      *p = 0x0;
52167910Sbrian      return MODE_NAK;
52278411Sbrian    } else
52367910Sbrian      return MODE_ACK;
52467910Sbrian  }
52567910Sbrian
52678411Sbrian  mval = MPPE_ConfigVal(cfg);
52778411Sbrian
52878411Sbrian  if (peer & ~MPPE_OPT_MASK)
52978411Sbrian    /* He's asking for bits we don't know about */
53078411Sbrian    res = MODE_NAK;
53178411Sbrian
53278411Sbrian  if (peer & MPPE_OPT_STATELESS) {
53378411Sbrian    if (cfg->mppe.state == MPPE_STATEFUL)
53478411Sbrian      /* Peer can't have stateless */
53578411Sbrian      res = MODE_NAK;
53678411Sbrian    else
53778411Sbrian      /* Peer wants stateless, that's ok */
53878411Sbrian      mval |= MPPE_OPT_STATELESS;
53978411Sbrian  } else {
54078411Sbrian    if (cfg->mppe.state == MPPE_STATELESS)
54178411Sbrian      /* Peer must have stateless */
54278411Sbrian      res = MODE_NAK;
54378411Sbrian    else
54478411Sbrian      /* Peer doesn't want stateless, that's ok */
54578411Sbrian      mval &= ~MPPE_OPT_STATELESS;
54667910Sbrian  }
54767910Sbrian
54878411Sbrian  /* If we've got a configured number of keybits - the peer must use that */
54978411Sbrian  if (cfg->mppe.keybits) {
55078411Sbrian    *p = htonl(mval);
55178411Sbrian    return peer == mval ? res : MODE_NAK;
55278411Sbrian  }
55367910Sbrian
55478411Sbrian  /* If a specific number of bits hasn't been requested, we'll need to NAK */
55578411Sbrian  switch (peer & MPPE_OPT_BITMASK) {
55678411Sbrian  case MPPE_OPT_128BIT:
55778411Sbrian  case MPPE_OPT_56BIT:
55878411Sbrian  case MPPE_OPT_40BIT:
55978411Sbrian    break;
56078411Sbrian  default:
56178411Sbrian    res = MODE_NAK;
56278411Sbrian  }
56378411Sbrian
56478411Sbrian  /* Suggest the best number of bits */
56578411Sbrian  mval &= ~MPPE_OPT_BITMASK;
56678411Sbrian  if (peer & MPPE_OPT_128BIT)
56778411Sbrian    mval |= MPPE_OPT_128BIT;
56878411Sbrian  else if (peer & MPPE_OPT_56BIT)
56978411Sbrian    mval |= MPPE_OPT_56BIT;
57078411Sbrian  else if (peer & MPPE_OPT_40BIT)
57178411Sbrian    mval |= MPPE_OPT_40BIT;
57278411Sbrian  else
57378411Sbrian    mval |= MPPE_OPT_128BIT;
57467910Sbrian  *p = htonl(mval);
57567910Sbrian
57678411Sbrian  return res;
57767910Sbrian}
57867910Sbrian
57978411Sbrianstatic struct mppe_state *
58078411SbrianMPPE_InitState(struct lcp_opt *o)
58178411Sbrian{
58278411Sbrian  struct mppe_state *mp;
58378411Sbrian  u_int32_t val;
58478411Sbrian
58578411Sbrian  if ((mp = calloc(1, sizeof *mp)) != NULL) {
58678411Sbrian    val = ntohl(*(u_int32_t *)o->data);
58778411Sbrian
58878411Sbrian    switch (val & MPPE_OPT_BITMASK) {
58978411Sbrian    case MPPE_OPT_128BIT:
59078411Sbrian      mp->keylen = 16;
59178411Sbrian      mp->keybits = 128;
59278411Sbrian      break;
59378411Sbrian    case MPPE_OPT_56BIT:
59478411Sbrian      mp->keylen = 8;
59578411Sbrian      mp->keybits = 56;
59678411Sbrian      break;
59778411Sbrian    case MPPE_OPT_40BIT:
59878411Sbrian      mp->keylen = 8;
59978411Sbrian      mp->keybits = 40;
60078411Sbrian      break;
60178411Sbrian    default:
60278411Sbrian      log_Printf(LogWARN, "Unexpected MPPE options 0x%08x\n", val);
60378411Sbrian      free(mp);
60478411Sbrian      return NULL;
60578411Sbrian    }
60678411Sbrian
60778411Sbrian    mp->stateless = !!(val & MPPE_OPT_STATELESS);
60878411Sbrian  }
60978411Sbrian
61078411Sbrian  return mp;
61178411Sbrian}
61278411Sbrian
61367910Sbrianstatic void *
61467910SbrianMPPEInitInput(struct lcp_opt *o)
61567910Sbrian{
61667910Sbrian  struct mppe_state *mip;
61767910Sbrian
61867910Sbrian  if (!MPPE_MasterKeyValid) {
61971971Sbrian    log_Printf(LogWARN, "MPPE: Cannot initialise without CHAP81\n");
62067910Sbrian    return NULL;
62167910Sbrian  }
62267910Sbrian
62378411Sbrian  if ((mip = MPPE_InitState(o)) == NULL) {
62478411Sbrian    log_Printf(LogWARN, "MPPEInput: Cannot initialise - unexpected options\n");
62578411Sbrian    return NULL;
62667910Sbrian  }
62767910Sbrian
62867910Sbrian  log_Printf(LogDEBUG, "MPPE: InitInput: %d-bits\n", mip->keybits);
62967910Sbrian
63068461Sbrian  GetAsymetricStartKey(MPPE_MasterKey, mip->mastkey, mip->keylen, 0,
63168461Sbrian                       MPPE_IsServer);
63267910Sbrian  GetNewKeyFromSHA(mip->mastkey, mip->mastkey, mip->keylen, mip->sesskey);
63367910Sbrian
63467910Sbrian  MPPEReduceSessionKey(mip);
63567910Sbrian
63678411Sbrian  log_Printf(LogCCP, "MPPE: Input channel initiated\n");
63767910Sbrian
63878411Sbrian  if (!mip->stateless) {
63978411Sbrian    /*
64078411Sbrian     * We need to initialise our dictionary here as the first packet we
64178411Sbrian     * receive is unlikely to have the FLUSHED bit set.
64278411Sbrian     */
64378411Sbrian    log_Printf(LogDEBUG, "MPPEInitInput: Dictionary initialised [%d]\n",
64478411Sbrian               mip->cohnum);
64578411Sbrian    RC4_set_key(&mip->rc4key, mip->keylen, mip->sesskey);
64678411Sbrian  } else {
64778411Sbrian    /*
64878411Sbrian     * We do the first key change here as the first packet is expected
64978411Sbrian     * to have a sequence number of 0 and we'll therefore not expect
65078411Sbrian     * to have to change the key at that point.
65178411Sbrian     */
65278411Sbrian    log_Printf(LogDEBUG, "MPPEInitInput: Key changed [%d]\n", mip->cohnum);
65378411Sbrian    MPPEKeyChange(mip);
65478411Sbrian  }
65567910Sbrian
65667910Sbrian  return mip;
65767910Sbrian}
65867910Sbrian
65967910Sbrianstatic void *
66067910SbrianMPPEInitOutput(struct lcp_opt *o)
66167910Sbrian{
66267910Sbrian  struct mppe_state *mop;
66367910Sbrian
66467910Sbrian  if (!MPPE_MasterKeyValid) {
66571971Sbrian    log_Printf(LogWARN, "MPPE: Cannot initialise without CHAP81\n");
66667910Sbrian    return NULL;
66767910Sbrian  }
66867910Sbrian
66978411Sbrian  if ((mop = MPPE_InitState(o)) == NULL) {
67078411Sbrian    log_Printf(LogWARN, "MPPEOutput: Cannot initialise - unexpected options\n");
67178411Sbrian    return NULL;
67267910Sbrian  }
67367910Sbrian
67467910Sbrian  log_Printf(LogDEBUG, "MPPE: InitOutput: %d-bits\n", mop->keybits);
67567910Sbrian
67668461Sbrian  GetAsymetricStartKey(MPPE_MasterKey, mop->mastkey, mop->keylen, 1,
67768461Sbrian                       MPPE_IsServer);
67867910Sbrian  GetNewKeyFromSHA(mop->mastkey, mop->mastkey, mop->keylen, mop->sesskey);
67967910Sbrian
68067910Sbrian  MPPEReduceSessionKey(mop);
68167910Sbrian
68278411Sbrian  log_Printf(LogCCP, "MPPE: Output channel initiated\n");
68367910Sbrian
68478411Sbrian  if (!mop->stateless) {
68578411Sbrian    /*
68678411Sbrian     * We need to initialise our dictionary now as the first packet we
68778411Sbrian     * send won't have the FLUSHED bit set.
68878411Sbrian     */
68978411Sbrian    log_Printf(LogDEBUG, "MPPEInitOutput: Dictionary initialised [%d]\n",
69078411Sbrian               mop->cohnum);
69178411Sbrian    RC4_set_key(&mop->rc4key, mop->keylen, mop->sesskey);
69278411Sbrian  }
69367910Sbrian
69467910Sbrian  return mop;
69567910Sbrian}
69667910Sbrian
69767910Sbrianstatic void
69867910SbrianMPPETermInput(void *v)
69967910Sbrian{
70067910Sbrian  free(v);
70167910Sbrian}
70267910Sbrian
70367910Sbrianstatic void
70467910SbrianMPPETermOutput(void *v)
70567910Sbrian{
70667910Sbrian  free(v);
70767910Sbrian}
70867910Sbrian
70967910Sbrianconst struct ccp_algorithm MPPEAlgorithm = {
71067910Sbrian  TY_MPPE,
71167910Sbrian  CCP_NEG_MPPE,
71267910Sbrian  MPPEDispOpts,
71372025Sbrian  MPPEUsable,
71478411Sbrian  MPPERequired,
71567910Sbrian  {
71667910Sbrian    MPPESetOptsInput,
71767910Sbrian    MPPEInitInput,
71867910Sbrian    MPPETermInput,
71967910Sbrian    MPPEResetInput,
72067910Sbrian    MPPEInput,
72167910Sbrian    MPPEDictSetup
72267910Sbrian  },
72367910Sbrian  {
72479165Sbrian    2,
72567910Sbrian    MPPEInitOptsOutput,
72667910Sbrian    MPPESetOptsOutput,
72767910Sbrian    MPPEInitOutput,
72867910Sbrian    MPPETermOutput,
72967910Sbrian    MPPEResetOutput,
73067910Sbrian    MPPEOutput
73167910Sbrian  },
73267910Sbrian};
733