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