mppe.c revision 92221
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 92221 2002-03-13 10:21:19Z brian $
2767910Sbrian */
2867910Sbrian
2967910Sbrian#include <sys/types.h>
3067910Sbrian
3190868Smike#include <arpa/inet.h>
3290868Smike
3367910Sbrian#include <stdio.h>
3467910Sbrian#include <stdlib.h>
3578411Sbrian#include <string.h>
3667910Sbrian#include <termios.h>
3768344Sbrian#ifdef __FreeBSD__
3867910Sbrian#include <sha.h>
3968344Sbrian#else
4068344Sbrian#include <openssl/sha.h>
4168344Sbrian#endif
4267910Sbrian#include <openssl/rc4.h>
4367910Sbrian
4467910Sbrian#include "defs.h"
4567910Sbrian#include "mbuf.h"
4667910Sbrian#include "log.h"
4767910Sbrian#include "timer.h"
4867910Sbrian#include "fsm.h"
4967910Sbrian#include "lqr.h"
5067910Sbrian#include "hdlc.h"
5167910Sbrian#include "lcp.h"
5267910Sbrian#include "ccp.h"
5372025Sbrian#include "throughput.h"
5472025Sbrian#include "layer.h"
5572025Sbrian#include "link.h"
5667910Sbrian#include "chap_ms.h"
5772025Sbrian#include "proto.h"
5867910Sbrian#include "mppe.h"
5983403Sbrian#include "ua.h"
6067910Sbrian
6167910Sbrian/*
6267910Sbrian * Documentation:
6367910Sbrian *
6467910Sbrian * draft-ietf-pppext-mppe-04.txt
6567910Sbrian * draft-ietf-pppext-mppe-keys-02.txt
6667910Sbrian */
6767910Sbrian
6878411Sbrian#define	MPPE_OPT_STATELESS	0x1000000
6978411Sbrian#define	MPPE_OPT_COMPRESSED	0x01
7078411Sbrian#define	MPPE_OPT_40BIT		0x20
7178411Sbrian#define	MPPE_OPT_56BIT		0x80
7278411Sbrian#define	MPPE_OPT_128BIT		0x40
7378411Sbrian#define	MPPE_OPT_BITMASK	0xe0
7478411Sbrian#define	MPPE_OPT_MASK		(MPPE_OPT_STATELESS | MPPE_OPT_BITMASK)
7578411Sbrian
7679376Sbrian#define	MPPE_FLUSHED			0x8000
7779376Sbrian#define	MPPE_ENCRYPTED			0x1000
7879376Sbrian#define	MPPE_HEADER_BITMASK		0xf000
7979376Sbrian#define	MPPE_HEADER_FLAG		0x00ff
8079376Sbrian#define	MPPE_HEADER_FLAGMASK		0x00ff
8179376Sbrian#define	MPPE_HEADER_FLAGSHIFT		8
8279376Sbrian#define	MPPE_HEADER_STATEFUL_KEYCHANGES	16
8378411Sbrian
8467910Sbrianstruct mppe_state {
8578411Sbrian  unsigned	stateless : 1;
8678411Sbrian  unsigned	flushnext : 1;
8778411Sbrian  unsigned	flushrequired : 1;
8878411Sbrian  int		cohnum;
8978411Sbrian  int		keylen;			/* 8 or 16 bytes */
9078411Sbrian  int 		keybits;		/* 40, 56 or 128 bits */
9178411Sbrian  char		sesskey[MPPE_KEY_LEN];
9278411Sbrian  char		mastkey[MPPE_KEY_LEN];
9378411Sbrian  RC4_KEY	rc4key;
9467910Sbrian};
9567910Sbrian
9667910Sbrianint MPPE_MasterKeyValid = 0;
9768461Sbrianint MPPE_IsServer = 0;
9867910Sbrianchar MPPE_MasterKey[MPPE_KEY_LEN];
9967910Sbrian
10078411Sbrian/*
10178411Sbrian * The peer has missed a packet.  Mark the next output frame to be FLUSHED
10278411Sbrian */
10378411Sbrianstatic int
10467910SbrianMPPEResetOutput(void *v)
10567910Sbrian{
10678411Sbrian  struct mppe_state *mop = (struct mppe_state *)v;
10778411Sbrian
10878411Sbrian  if (mop->stateless)
10978411Sbrian    log_Printf(LogCCP, "MPPE: Unexpected output channel reset\n");
11078411Sbrian  else {
11178411Sbrian    log_Printf(LogCCP, "MPPE: Output channel reset\n");
11278411Sbrian    mop->flushnext = 1;
11378411Sbrian  }
11478411Sbrian
11578411Sbrian  return 0;		/* Ask FSM not to ACK */
11667910Sbrian}
11767910Sbrian
11867912Sbrianstatic void
11967912SbrianMPPEReduceSessionKey(struct mppe_state *mp)
12067912Sbrian{
12167910Sbrian  switch(mp->keybits) {
12267910Sbrian  case 40:
12367910Sbrian    mp->sesskey[2] = 0x9e;
12467910Sbrian    mp->sesskey[1] = 0x26;
12567910Sbrian  case 56:
12667910Sbrian    mp->sesskey[0] = 0xd1;
12767910Sbrian  case 128:
12867910Sbrian  }
12967910Sbrian}
13067910Sbrian
13167912Sbrianstatic void
13267912SbrianMPPEKeyChange(struct mppe_state *mp)
13367912Sbrian{
13467910Sbrian  char InterimKey[MPPE_KEY_LEN];
13567910Sbrian  RC4_KEY RC4Key;
13667910Sbrian
13767910Sbrian  GetNewKeyFromSHA(mp->mastkey, mp->sesskey, mp->keylen, InterimKey);
13867910Sbrian  RC4_set_key(&RC4Key, mp->keylen, InterimKey);
13967910Sbrian  RC4(&RC4Key, mp->keylen, InterimKey, mp->sesskey);
14067910Sbrian
14167910Sbrian  MPPEReduceSessionKey(mp);
14267910Sbrian}
14367910Sbrian
14467910Sbrianstatic struct mbuf *
14567910SbrianMPPEOutput(void *v, struct ccp *ccp, struct link *l, int pri, u_short *proto,
14667910Sbrian           struct mbuf *mp)
14767910Sbrian{
14867910Sbrian  struct mppe_state *mop = (struct mppe_state *)v;
14967910Sbrian  struct mbuf *mo;
15078411Sbrian  u_short nproto, prefix;
15178411Sbrian  int dictinit, ilen, len;
15267910Sbrian  char *rp;
15367910Sbrian
15467910Sbrian  ilen = m_length(mp);
15578411Sbrian  dictinit = 0;
15667910Sbrian
15767910Sbrian  log_Printf(LogDEBUG, "MPPE: Output: Proto %02x (%d bytes)\n", *proto, ilen);
15867910Sbrian  if (*proto < 0x21 && *proto > 0xFA) {
15967910Sbrian    log_Printf(LogDEBUG, "MPPE: Output: Not encrypting\n");
16078411Sbrian    ccp->compout += ilen;
16178411Sbrian    ccp->uncompout += ilen;
16267910Sbrian    return mp;
16367910Sbrian  }
16467910Sbrian
16567910Sbrian  log_DumpBp(LogDEBUG, "MPPE: Output: Encrypt packet:", mp);
16667910Sbrian
16767910Sbrian  /* Get mbuf for prefixes */
16867910Sbrian  mo = m_get(4, MB_CCPOUT);
16967910Sbrian  mo->m_next = mp;
17067910Sbrian
17178411Sbrian  rp = MBUF_CTOP(mo);
17278411Sbrian  prefix = MPPE_ENCRYPTED | mop->cohnum;
17367910Sbrian
17478411Sbrian  if (mop->stateless ||
17578411Sbrian      (mop->cohnum & MPPE_HEADER_FLAGMASK) == MPPE_HEADER_FLAG) {
17678411Sbrian    /* Change our key */
17778411Sbrian    log_Printf(LogDEBUG, "MPPEOutput: Key changed [%d]\n", mop->cohnum);
17878411Sbrian    MPPEKeyChange(mop);
17978411Sbrian    dictinit = 1;
18078411Sbrian  }
18178411Sbrian
18278411Sbrian  if (mop->stateless || mop->flushnext) {
18378411Sbrian    prefix |= MPPE_FLUSHED;
18478411Sbrian    dictinit = 1;
18578411Sbrian    mop->flushnext = 0;
18678411Sbrian  }
18778411Sbrian
18878411Sbrian  if (dictinit) {
18978411Sbrian    /* Initialise our dictionary */
19078411Sbrian    log_Printf(LogDEBUG, "MPPEOutput: Dictionary initialised [%d]\n",
19178411Sbrian               mop->cohnum);
19278411Sbrian    RC4_set_key(&mop->rc4key, mop->keylen, mop->sesskey);
19378411Sbrian  }
19478411Sbrian
19567910Sbrian  /* Set MPPE packet prefix */
19683403Sbrian  ua_htons(&prefix, rp);
19767910Sbrian
19867910Sbrian  /* Save encrypted protocol number */
19967910Sbrian  nproto = htons(*proto);
20067910Sbrian  RC4(&mop->rc4key, 2, (char *)&nproto, rp + 2);
20167910Sbrian
20267910Sbrian  /* Encrypt main packet */
20367910Sbrian  rp = MBUF_CTOP(mp);
20467910Sbrian  RC4(&mop->rc4key, ilen, rp, rp);
20567910Sbrian
20678411Sbrian  mop->cohnum++;
20778411Sbrian  mop->cohnum &= ~MPPE_HEADER_BITMASK;
20867910Sbrian
20978411Sbrian  /* Set the protocol number */
21067910Sbrian  *proto = ccp_Proto(ccp);
21178411Sbrian  len = m_length(mo);
21278411Sbrian  ccp->uncompout += ilen;
21378411Sbrian  ccp->compout += len;
21467910Sbrian
21567912Sbrian  log_Printf(LogDEBUG, "MPPE: Output: Encrypted: Proto %02x (%d bytes)\n",
21678411Sbrian             *proto, len);
21767910Sbrian
21867910Sbrian  return mo;
21967910Sbrian}
22067910Sbrian
22167910Sbrianstatic void
22267910SbrianMPPEResetInput(void *v)
22367910Sbrian{
22478411Sbrian  log_Printf(LogCCP, "MPPE: Unexpected input channel ack\n");
22567910Sbrian}
22667910Sbrian
22767910Sbrianstatic struct mbuf *
22867910SbrianMPPEInput(void *v, struct ccp *ccp, u_short *proto, struct mbuf *mp)
22967910Sbrian{
23067910Sbrian  struct mppe_state *mip = (struct mppe_state *)v;
23167910Sbrian  u_short prefix;
23267910Sbrian  char *rp;
23378411Sbrian  int dictinit, flushed, ilen, len, n;
23467910Sbrian
23567910Sbrian  ilen = m_length(mp);
23678411Sbrian  dictinit = 0;
23778411Sbrian  ccp->compin += ilen;
23867910Sbrian
23967910Sbrian  log_Printf(LogDEBUG, "MPPE: Input: Proto %02x (%d bytes)\n", *proto, ilen);
24067910Sbrian  log_DumpBp(LogDEBUG, "MPPE: Input: Packet:", mp);
24167910Sbrian
24267910Sbrian  mp = mbuf_Read(mp, &prefix, 2);
24367910Sbrian  prefix = ntohs(prefix);
24478411Sbrian  flushed = prefix & MPPE_FLUSHED;
24578411Sbrian  prefix &= ~flushed;
24678411Sbrian  if ((prefix & MPPE_HEADER_BITMASK) != MPPE_ENCRYPTED) {
24778411Sbrian    log_Printf(LogERROR, "MPPE: Input: Invalid packet (flags = 0x%x)\n",
24878411Sbrian               (prefix & MPPE_HEADER_BITMASK) | flushed);
24967910Sbrian    m_freem(mp);
25067910Sbrian    return NULL;
25167910Sbrian  }
25267910Sbrian
25378411Sbrian  prefix &= ~MPPE_HEADER_BITMASK;
25478411Sbrian
25578411Sbrian  if (!flushed && mip->stateless) {
25678411Sbrian    log_Printf(LogCCP, "MPPEInput: Packet without MPPE_FLUSHED set"
25778411Sbrian               " in stateless mode\n");
25878411Sbrian    flushed = MPPE_FLUSHED;
25978411Sbrian    /* Should we really continue ? */
26067910Sbrian  }
26167910Sbrian
26278411Sbrian  if (mip->stateless) {
26378411Sbrian    /* Change our key for each missed packet in stateless mode */
26478411Sbrian    while (prefix != mip->cohnum) {
26578411Sbrian      log_Printf(LogDEBUG, "MPPEInput: Key changed [%u]\n", prefix);
26678411Sbrian      MPPEKeyChange(mip);
26778411Sbrian      /*
26878411Sbrian       * mip->cohnum contains what we received last time in stateless
26978411Sbrian       * mode.
27078411Sbrian       */
27178411Sbrian      mip->cohnum++;
27278411Sbrian      mip->cohnum &= ~MPPE_HEADER_BITMASK;
27378411Sbrian    }
27478411Sbrian    dictinit = 1;
27578411Sbrian  } else {
27678411Sbrian    if (flushed) {
27778411Sbrian      /*
27878411Sbrian       * We can always process a flushed packet.
27978411Sbrian       * Catch up on any outstanding key changes.
28078411Sbrian       */
28178411Sbrian      n = (prefix >> MPPE_HEADER_FLAGSHIFT) -
28278411Sbrian          (mip->cohnum >> MPPE_HEADER_FLAGSHIFT);
28379376Sbrian      if (n < 0)
28479376Sbrian        n += MPPE_HEADER_STATEFUL_KEYCHANGES;
28578411Sbrian      while (n--) {
28678411Sbrian        log_Printf(LogDEBUG, "MPPEInput: Key changed during catchup [%u]\n",
28778411Sbrian                   prefix);
28878411Sbrian        MPPEKeyChange(mip);
28978411Sbrian      }
29078411Sbrian      mip->flushrequired = 0;
29178411Sbrian      mip->cohnum = prefix;
29278411Sbrian      dictinit = 1;
29378411Sbrian    }
29467910Sbrian
29578411Sbrian    if (mip->flushrequired) {
29678411Sbrian      /*
29778411Sbrian       * Perhaps we should be lenient if
29878411Sbrian       * (prefix & MPPE_HEADER_FLAGMASK) == MPPE_HEADER_FLAG
29978411Sbrian       * The spec says that we shouldn't be though....
30078411Sbrian       */
30178411Sbrian      log_Printf(LogDEBUG, "MPPE: Not flushed - discarded\n");
30282411Sbrian      fsm_Output(&ccp->fsm, CODE_RESETREQ, ccp->fsm.reqid++, NULL, 0,
30382411Sbrian                 MB_CCPOUT);
30478411Sbrian      m_freem(mp);
30578411Sbrian      return NULL;
30678411Sbrian    }
30778411Sbrian
30878411Sbrian    if (prefix != mip->cohnum) {
30978411Sbrian      /*
31078411Sbrian       * We're in stateful mode and didn't receive the expected
31178411Sbrian       * packet.  Send a reset request, but don't tell the CCP layer
31278411Sbrian       * about it as we don't expect to receive a Reset ACK !
31378411Sbrian       * Guess what... M$ invented this !
31478411Sbrian       */
31578411Sbrian      log_Printf(LogCCP, "MPPE: Input: Got seq %u, not %u\n",
31678411Sbrian                 prefix, mip->cohnum);
31778411Sbrian      fsm_Output(&ccp->fsm, CODE_RESETREQ, ccp->fsm.reqid++, NULL, 0,
31878411Sbrian                 MB_CCPOUT);
31978411Sbrian      mip->flushrequired = 1;
32078411Sbrian      m_freem(mp);
32178411Sbrian      return NULL;
32278411Sbrian    }
32378411Sbrian
32478411Sbrian    if ((prefix & MPPE_HEADER_FLAGMASK) == MPPE_HEADER_FLAG) {
32578411Sbrian      log_Printf(LogDEBUG, "MPPEInput: Key changed [%u]\n", prefix);
32678411Sbrian      MPPEKeyChange(mip);
32778411Sbrian      dictinit = 1;
32878411Sbrian    } else if (flushed)
32978411Sbrian      dictinit = 1;
33078411Sbrian
33178411Sbrian    /*
33278411Sbrian     * mip->cohnum contains what we expect to receive next time in stateful
33378411Sbrian     * mode.
33478411Sbrian     */
33578411Sbrian    mip->cohnum++;
33678411Sbrian    mip->cohnum &= ~MPPE_HEADER_BITMASK;
33778411Sbrian  }
33878411Sbrian
33978411Sbrian  if (dictinit) {
34078411Sbrian    log_Printf(LogDEBUG, "MPPEInput: Dictionary initialised [%u]\n", prefix);
34178411Sbrian    RC4_set_key(&mip->rc4key, mip->keylen, mip->sesskey);
34278411Sbrian  }
34378411Sbrian
34467910Sbrian  mp = mbuf_Read(mp, proto, 2);
34567910Sbrian  RC4(&mip->rc4key, 2, (char *)proto, (char *)proto);
34667910Sbrian  *proto = ntohs(*proto);
34767910Sbrian
34867910Sbrian  rp = MBUF_CTOP(mp);
34978411Sbrian  len = m_length(mp);
35078411Sbrian  RC4(&mip->rc4key, len, rp, rp);
35167910Sbrian
35278411Sbrian  log_Printf(LogDEBUG, "MPPEInput: Decrypted: Proto %02x (%d bytes)\n",
35378411Sbrian             *proto, len);
35478411Sbrian  log_DumpBp(LogDEBUG, "MPPEInput: Decrypted: Packet:", mp);
35567910Sbrian
35678411Sbrian  ccp->uncompin += len;
35767910Sbrian
35867910Sbrian  return mp;
35967910Sbrian}
36067910Sbrian
36167910Sbrianstatic void
36267910SbrianMPPEDictSetup(void *v, struct ccp *ccp, u_short proto, struct mbuf *mi)
36367910Sbrian{
36467910Sbrian}
36567910Sbrian
36667910Sbrianstatic const char *
36767910SbrianMPPEDispOpts(struct lcp_opt *o)
36867910Sbrian{
36978411Sbrian  static char buf[70];
37083403Sbrian  u_int32_t val;
37178411Sbrian  char ch;
37292221Sbrian  int len, n;
37378411Sbrian
37483403Sbrian  ua_ntohl(o->data, &val);
37592221Sbrian  len = 0;
37692221Sbrian  if ((n = snprintf(buf, sizeof buf, "value 0x%08x ", (unsigned)val)) > 0)
37792221Sbrian    len += n;
37878411Sbrian  if (!(val & MPPE_OPT_BITMASK)) {
37992221Sbrian    if ((n = snprintf(buf + len, sizeof buf - len, "(0")) > 0)
38092221Sbrian      len += n;
38178411Sbrian  } else {
38278411Sbrian    ch = '(';
38378411Sbrian    if (val & MPPE_OPT_128BIT) {
38492221Sbrian      if ((n = snprintf(buf + len, sizeof buf - len, "%c128", ch)) > 0)
38592221Sbrian        len += n;
38678411Sbrian      ch = '/';
38778411Sbrian    }
38878411Sbrian    if (val & MPPE_OPT_56BIT) {
38992221Sbrian      if ((n = snprintf(buf + len, sizeof buf - len, "%c56", ch)) > 0)
39092221Sbrian        len += n;
39178411Sbrian      ch = '/';
39278411Sbrian    }
39378411Sbrian    if (val & MPPE_OPT_40BIT) {
39492221Sbrian      if ((n = snprintf(buf + len, sizeof buf - len, "%c40", ch)) > 0)
39592221Sbrian        len += n;
39678411Sbrian      ch = '/';
39778411Sbrian    }
39878411Sbrian  }
39978411Sbrian
40092221Sbrian  if ((n = snprintf(buf + len, sizeof buf - len, " bits, state%s",
40192221Sbrian                    (val & MPPE_OPT_STATELESS) ? "less" : "ful")) > 0)
40292221Sbrian    len += n;
40378411Sbrian
40478411Sbrian  if (val & MPPE_OPT_COMPRESSED) {
40592221Sbrian    if ((n = snprintf(buf + len, sizeof buf - len, ", compressed")) > 0)
40692221Sbrian      len += n;
40778411Sbrian  }
40878411Sbrian
40978411Sbrian  snprintf(buf + len, sizeof buf - len, ")");
41078411Sbrian
41167910Sbrian  return buf;
41267910Sbrian}
41367910Sbrian
41472025Sbrianstatic int
41572025SbrianMPPEUsable(struct fsm *fp)
41672025Sbrian{
41772025Sbrian  struct lcp *lcp;
41872025Sbrian  int ok;
41972025Sbrian
42072025Sbrian  lcp = &fp->link->lcp;
42172025Sbrian  ok = (lcp->want_auth == PROTO_CHAP && lcp->want_authtype == 0x81) ||
42272025Sbrian       (lcp->his_auth == PROTO_CHAP && lcp->his_authtype == 0x81);
42372025Sbrian  if (!ok)
42472025Sbrian    log_Printf(LogCCP, "MPPE: Not usable without CHAP81\n");
42572025Sbrian
42672025Sbrian  return ok;
42772025Sbrian}
42872025Sbrian
42978411Sbrianstatic int
43078411SbrianMPPERequired(struct fsm *fp)
43178411Sbrian{
43278411Sbrian  return fp->link->ccp.cfg.mppe.required;
43378411Sbrian}
43478411Sbrian
43578411Sbrianstatic u_int32_t
43678411SbrianMPPE_ConfigVal(const struct ccp_config *cfg)
43778411Sbrian{
43878411Sbrian  u_int32_t val;
43978411Sbrian
44078411Sbrian  val = cfg->mppe.state == MPPE_STATELESS ? MPPE_OPT_STATELESS : 0;
44178411Sbrian  switch(cfg->mppe.keybits) {
44278411Sbrian  case 128:
44378411Sbrian    val |= MPPE_OPT_128BIT;
44478411Sbrian    break;
44578411Sbrian  case 56:
44678411Sbrian    val |= MPPE_OPT_56BIT;
44778411Sbrian    break;
44878411Sbrian  case 40:
44978411Sbrian    val |= MPPE_OPT_40BIT;
45078411Sbrian    break;
45178411Sbrian  case 0:
45278411Sbrian    val |= MPPE_OPT_128BIT | MPPE_OPT_56BIT | MPPE_OPT_40BIT;
45378411Sbrian    break;
45478411Sbrian  }
45578411Sbrian
45678411Sbrian  return val;
45778411Sbrian}
45878411Sbrian
45978411Sbrian/*
46078411Sbrian * What options should we use for our first configure request
46178411Sbrian */
46267910Sbrianstatic void
46367910SbrianMPPEInitOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg)
46467910Sbrian{
46583403Sbrian  u_int32_t mval;
46667910Sbrian
46767910Sbrian  o->len = 6;
46867910Sbrian
46967910Sbrian  if (!MPPE_MasterKeyValid) {
47070498Sbrian    log_Printf(LogCCP, "MPPE: MasterKey is invalid,"
47171971Sbrian               " MPPE is available only with CHAP81 authentication\n");
47283403Sbrian    ua_htonl(0x0, o->data);
47367910Sbrian    return;
47467910Sbrian  }
47567910Sbrian
47683403Sbrian  mval = MPPE_ConfigVal(cfg);
47783403Sbrian  ua_htonl(&mval, o->data);
47867910Sbrian}
47967910Sbrian
48078411Sbrian/*
48178411Sbrian * Our CCP request was NAK'd with the given options
48278411Sbrian */
48367910Sbrianstatic int
48478411SbrianMPPESetOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg)
48567910Sbrian{
48683403Sbrian  u_int32_t mval, peer;
48767910Sbrian
48883403Sbrian  ua_ntohl(o->data, &peer);
48983403Sbrian
49078411Sbrian  if (!MPPE_MasterKeyValid)
49178411Sbrian    /* Treat their NAK as a REJ */
49278411Sbrian    return MODE_NAK;
49367910Sbrian
49478411Sbrian  mval = MPPE_ConfigVal(cfg);
49578411Sbrian
49678411Sbrian  /*
49778411Sbrian   * If we haven't been configured with a specific number of keybits, allow
49878411Sbrian   * whatever the peer asks for.
49978411Sbrian   */
50078411Sbrian  if (!cfg->mppe.keybits) {
50178411Sbrian    mval &= ~MPPE_OPT_BITMASK;
50278411Sbrian    mval |= (peer & MPPE_OPT_BITMASK);
50378411Sbrian    if (!(mval & MPPE_OPT_BITMASK))
50478411Sbrian      mval |= MPPE_OPT_128BIT;
50567910Sbrian  }
50667910Sbrian
50778411Sbrian  /* Adjust our statelessness */
50878411Sbrian  if (cfg->mppe.state == MPPE_ANYSTATE) {
50978411Sbrian    mval &= ~MPPE_OPT_STATELESS;
51078411Sbrian    mval |= (peer & MPPE_OPT_STATELESS);
51178411Sbrian  }
51267910Sbrian
51383403Sbrian  ua_htonl(&mval, o->data);
51478411Sbrian
51578411Sbrian  return MODE_ACK;
51667910Sbrian}
51767910Sbrian
51878411Sbrian/*
51978411Sbrian * The peer has requested the given options
52078411Sbrian */
52167910Sbrianstatic int
52267910SbrianMPPESetOptsInput(struct lcp_opt *o, const struct ccp_config *cfg)
52367910Sbrian{
52483403Sbrian  u_int32_t mval, peer;
52578411Sbrian  int res = MODE_ACK;
52667910Sbrian
52783403Sbrian  ua_ntohl(o->data, &peer);
52867910Sbrian  if (!MPPE_MasterKeyValid) {
52983403Sbrian    if (peer != 0) {
53083403Sbrian      peer = 0;
53183403Sbrian      ua_htonl(&peer, o->data);
53267910Sbrian      return MODE_NAK;
53378411Sbrian    } else
53467910Sbrian      return MODE_ACK;
53567910Sbrian  }
53667910Sbrian
53778411Sbrian  mval = MPPE_ConfigVal(cfg);
53878411Sbrian
53978411Sbrian  if (peer & ~MPPE_OPT_MASK)
54078411Sbrian    /* He's asking for bits we don't know about */
54178411Sbrian    res = MODE_NAK;
54278411Sbrian
54378411Sbrian  if (peer & MPPE_OPT_STATELESS) {
54478411Sbrian    if (cfg->mppe.state == MPPE_STATEFUL)
54578411Sbrian      /* Peer can't have stateless */
54678411Sbrian      res = MODE_NAK;
54778411Sbrian    else
54878411Sbrian      /* Peer wants stateless, that's ok */
54978411Sbrian      mval |= MPPE_OPT_STATELESS;
55078411Sbrian  } else {
55178411Sbrian    if (cfg->mppe.state == MPPE_STATELESS)
55278411Sbrian      /* Peer must have stateless */
55378411Sbrian      res = MODE_NAK;
55478411Sbrian    else
55578411Sbrian      /* Peer doesn't want stateless, that's ok */
55678411Sbrian      mval &= ~MPPE_OPT_STATELESS;
55767910Sbrian  }
55867910Sbrian
55978411Sbrian  /* If we've got a configured number of keybits - the peer must use that */
56078411Sbrian  if (cfg->mppe.keybits) {
56183403Sbrian    ua_htonl(&mval, o->data);
56278411Sbrian    return peer == mval ? res : MODE_NAK;
56378411Sbrian  }
56467910Sbrian
56578411Sbrian  /* If a specific number of bits hasn't been requested, we'll need to NAK */
56678411Sbrian  switch (peer & MPPE_OPT_BITMASK) {
56778411Sbrian  case MPPE_OPT_128BIT:
56878411Sbrian  case MPPE_OPT_56BIT:
56978411Sbrian  case MPPE_OPT_40BIT:
57078411Sbrian    break;
57178411Sbrian  default:
57278411Sbrian    res = MODE_NAK;
57378411Sbrian  }
57478411Sbrian
57578411Sbrian  /* Suggest the best number of bits */
57678411Sbrian  mval &= ~MPPE_OPT_BITMASK;
57778411Sbrian  if (peer & MPPE_OPT_128BIT)
57878411Sbrian    mval |= MPPE_OPT_128BIT;
57978411Sbrian  else if (peer & MPPE_OPT_56BIT)
58078411Sbrian    mval |= MPPE_OPT_56BIT;
58178411Sbrian  else if (peer & MPPE_OPT_40BIT)
58278411Sbrian    mval |= MPPE_OPT_40BIT;
58378411Sbrian  else
58478411Sbrian    mval |= MPPE_OPT_128BIT;
58583403Sbrian  ua_htonl(&mval, o->data);
58667910Sbrian
58778411Sbrian  return res;
58867910Sbrian}
58967910Sbrian
59078411Sbrianstatic struct mppe_state *
59178411SbrianMPPE_InitState(struct lcp_opt *o)
59278411Sbrian{
59378411Sbrian  struct mppe_state *mp;
59478411Sbrian  u_int32_t val;
59578411Sbrian
59678411Sbrian  if ((mp = calloc(1, sizeof *mp)) != NULL) {
59783403Sbrian    ua_ntohl(o->data, &val);
59878411Sbrian
59978411Sbrian    switch (val & MPPE_OPT_BITMASK) {
60078411Sbrian    case MPPE_OPT_128BIT:
60178411Sbrian      mp->keylen = 16;
60278411Sbrian      mp->keybits = 128;
60378411Sbrian      break;
60478411Sbrian    case MPPE_OPT_56BIT:
60578411Sbrian      mp->keylen = 8;
60678411Sbrian      mp->keybits = 56;
60778411Sbrian      break;
60878411Sbrian    case MPPE_OPT_40BIT:
60978411Sbrian      mp->keylen = 8;
61078411Sbrian      mp->keybits = 40;
61178411Sbrian      break;
61278411Sbrian    default:
61378411Sbrian      log_Printf(LogWARN, "Unexpected MPPE options 0x%08x\n", val);
61478411Sbrian      free(mp);
61578411Sbrian      return NULL;
61678411Sbrian    }
61778411Sbrian
61878411Sbrian    mp->stateless = !!(val & MPPE_OPT_STATELESS);
61978411Sbrian  }
62078411Sbrian
62178411Sbrian  return mp;
62278411Sbrian}
62378411Sbrian
62467910Sbrianstatic void *
62567910SbrianMPPEInitInput(struct lcp_opt *o)
62667910Sbrian{
62767910Sbrian  struct mppe_state *mip;
62867910Sbrian
62967910Sbrian  if (!MPPE_MasterKeyValid) {
63071971Sbrian    log_Printf(LogWARN, "MPPE: Cannot initialise without CHAP81\n");
63167910Sbrian    return NULL;
63267910Sbrian  }
63367910Sbrian
63478411Sbrian  if ((mip = MPPE_InitState(o)) == NULL) {
63578411Sbrian    log_Printf(LogWARN, "MPPEInput: Cannot initialise - unexpected options\n");
63678411Sbrian    return NULL;
63767910Sbrian  }
63867910Sbrian
63967910Sbrian  log_Printf(LogDEBUG, "MPPE: InitInput: %d-bits\n", mip->keybits);
64067910Sbrian
64168461Sbrian  GetAsymetricStartKey(MPPE_MasterKey, mip->mastkey, mip->keylen, 0,
64268461Sbrian                       MPPE_IsServer);
64367910Sbrian  GetNewKeyFromSHA(mip->mastkey, mip->mastkey, mip->keylen, mip->sesskey);
64467910Sbrian
64567910Sbrian  MPPEReduceSessionKey(mip);
64667910Sbrian
64778411Sbrian  log_Printf(LogCCP, "MPPE: Input channel initiated\n");
64867910Sbrian
64978411Sbrian  if (!mip->stateless) {
65078411Sbrian    /*
65178411Sbrian     * We need to initialise our dictionary here as the first packet we
65278411Sbrian     * receive is unlikely to have the FLUSHED bit set.
65378411Sbrian     */
65478411Sbrian    log_Printf(LogDEBUG, "MPPEInitInput: Dictionary initialised [%d]\n",
65578411Sbrian               mip->cohnum);
65678411Sbrian    RC4_set_key(&mip->rc4key, mip->keylen, mip->sesskey);
65778411Sbrian  } else {
65878411Sbrian    /*
65978411Sbrian     * We do the first key change here as the first packet is expected
66078411Sbrian     * to have a sequence number of 0 and we'll therefore not expect
66178411Sbrian     * to have to change the key at that point.
66278411Sbrian     */
66378411Sbrian    log_Printf(LogDEBUG, "MPPEInitInput: Key changed [%d]\n", mip->cohnum);
66478411Sbrian    MPPEKeyChange(mip);
66578411Sbrian  }
66667910Sbrian
66767910Sbrian  return mip;
66867910Sbrian}
66967910Sbrian
67067910Sbrianstatic void *
67167910SbrianMPPEInitOutput(struct lcp_opt *o)
67267910Sbrian{
67367910Sbrian  struct mppe_state *mop;
67467910Sbrian
67567910Sbrian  if (!MPPE_MasterKeyValid) {
67671971Sbrian    log_Printf(LogWARN, "MPPE: Cannot initialise without CHAP81\n");
67767910Sbrian    return NULL;
67867910Sbrian  }
67967910Sbrian
68078411Sbrian  if ((mop = MPPE_InitState(o)) == NULL) {
68178411Sbrian    log_Printf(LogWARN, "MPPEOutput: Cannot initialise - unexpected options\n");
68278411Sbrian    return NULL;
68367910Sbrian  }
68467910Sbrian
68567910Sbrian  log_Printf(LogDEBUG, "MPPE: InitOutput: %d-bits\n", mop->keybits);
68667910Sbrian
68768461Sbrian  GetAsymetricStartKey(MPPE_MasterKey, mop->mastkey, mop->keylen, 1,
68868461Sbrian                       MPPE_IsServer);
68967910Sbrian  GetNewKeyFromSHA(mop->mastkey, mop->mastkey, mop->keylen, mop->sesskey);
69067910Sbrian
69167910Sbrian  MPPEReduceSessionKey(mop);
69267910Sbrian
69378411Sbrian  log_Printf(LogCCP, "MPPE: Output channel initiated\n");
69467910Sbrian
69578411Sbrian  if (!mop->stateless) {
69678411Sbrian    /*
69778411Sbrian     * We need to initialise our dictionary now as the first packet we
69878411Sbrian     * send won't have the FLUSHED bit set.
69978411Sbrian     */
70078411Sbrian    log_Printf(LogDEBUG, "MPPEInitOutput: Dictionary initialised [%d]\n",
70178411Sbrian               mop->cohnum);
70278411Sbrian    RC4_set_key(&mop->rc4key, mop->keylen, mop->sesskey);
70378411Sbrian  }
70467910Sbrian
70567910Sbrian  return mop;
70667910Sbrian}
70767910Sbrian
70867910Sbrianstatic void
70967910SbrianMPPETermInput(void *v)
71067910Sbrian{
71167910Sbrian  free(v);
71267910Sbrian}
71367910Sbrian
71467910Sbrianstatic void
71567910SbrianMPPETermOutput(void *v)
71667910Sbrian{
71767910Sbrian  free(v);
71867910Sbrian}
71967910Sbrian
72067910Sbrianconst struct ccp_algorithm MPPEAlgorithm = {
72167910Sbrian  TY_MPPE,
72267910Sbrian  CCP_NEG_MPPE,
72367910Sbrian  MPPEDispOpts,
72472025Sbrian  MPPEUsable,
72578411Sbrian  MPPERequired,
72667910Sbrian  {
72767910Sbrian    MPPESetOptsInput,
72867910Sbrian    MPPEInitInput,
72967910Sbrian    MPPETermInput,
73067910Sbrian    MPPEResetInput,
73167910Sbrian    MPPEInput,
73267910Sbrian    MPPEDictSetup
73367910Sbrian  },
73467910Sbrian  {
73579165Sbrian    2,
73667910Sbrian    MPPEInitOptsOutput,
73767910Sbrian    MPPESetOptsOutput,
73867910Sbrian    MPPEInitOutput,
73967910Sbrian    MPPETermOutput,
74067910Sbrian    MPPEResetOutput,
74167910Sbrian    MPPEOutput
74267910Sbrian  },
74367910Sbrian};
744