summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
authorbrian <brian@FreeBSD.org>2000-10-30 00:15:04 +0000
committerbrian <brian@FreeBSD.org>2000-10-30 00:15:04 +0000
commit06792c58d5296e43c29af28744e2aa418b29c02c (patch)
treeb3faf577f26b4b6238bf2ed28bb1cced590c6645 /usr.sbin
parentc238c956a4e688205b311cfc63717fc84e6d43eb (diff)
downloadFreeBSD-src-06792c58d5296e43c29af28744e2aa418b29c02c.zip
FreeBSD-src-06792c58d5296e43c29af28744e2aa418b29c02c.tar.gz
Add MPPE and MSChap v2 support (denied and disabled by default)
Submitted by: Ustimenko Semen <semen@iclub.nsu.ru>
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/ppp/Makefile2
-rw-r--r--usr.sbin/ppp/ccp.c18
-rw-r--r--usr.sbin/ppp/ccp.h11
-rw-r--r--usr.sbin/ppp/chap.c160
-rw-r--r--usr.sbin/ppp/chap.h4
-rw-r--r--usr.sbin/ppp/chap_ms.c233
-rw-r--r--usr.sbin/ppp/chap_ms.h16
-rw-r--r--usr.sbin/ppp/command.c40
-rw-r--r--usr.sbin/ppp/defs.h1
-rw-r--r--usr.sbin/ppp/lcp.c37
-rw-r--r--usr.sbin/ppp/lcp.h1
-rw-r--r--usr.sbin/ppp/mppe.c422
-rw-r--r--usr.sbin/ppp/mppe.h32
-rw-r--r--usr.sbin/ppp/ppp.826
-rw-r--r--usr.sbin/ppp/ppp.8.m426
15 files changed, 1003 insertions, 26 deletions
diff --git a/usr.sbin/ppp/Makefile b/usr.sbin/ppp/Makefile
index 48ec394..f4e5eec 100644
--- a/usr.sbin/ppp/Makefile
+++ b/usr.sbin/ppp/Makefile
@@ -58,7 +58,7 @@ SRCS+= id.c
.if exists(${.CURDIR}/../../secure) && !defined(NOCRYPT) && !defined(NOSECURE) && !defined(NO_OPENSSL) && !defined(RELEASE_CRUNCH)
DISTRIBUTION=crypto
CFLAGS+=-DHAVE_DES
-SRCS+= chap_ms.c
+SRCS+= chap_ms.c mppe.c
LDADD+= -lcrypto
DPADD+= ${LIBCRYPTO}
.endif
diff --git a/usr.sbin/ppp/ccp.c b/usr.sbin/ppp/ccp.c
index e7df030..4366863 100644
--- a/usr.sbin/ppp/ccp.c
+++ b/usr.sbin/ppp/ccp.c
@@ -61,6 +61,9 @@
#ifndef NORADIUS
#include "radius.h"
#endif
+#ifdef HAVE_DES
+#include "mppe.h"
+#endif
#include "bundle.h"
static void CcpSendConfigReq(struct fsm *);
@@ -106,7 +109,8 @@ protoname(int proto)
NULL, NULL, NULL, NULL, NULL, NULL,
"HWPPC", /* 16: Hewlett-Packard PPC */
"STAC", /* 17: Stac Electronics LZS (rfc1974) */
- "MPPC", /* 18: Microsoft PPC (rfc2118) */
+ "MPPE", /* 18: Microsoft PPC (rfc2118) and */
+ /* Microsoft PPE (draft-ietf-pppext-mppe) */
"GAND", /* 19: Gandalf FZA (rfc1993) */
"V42BIS", /* 20: ARG->DATA.42bis compression */
"BSD", /* 21: BSD LZW Compress */
@@ -130,6 +134,9 @@ static const struct ccp_algorithm * const algorithm[] = {
&DeflateAlgorithm,
&Pred1Algorithm,
&PppdDeflateAlgorithm
+#ifdef HAVE_DES
+ , &MPPEAlgorithm
+#endif
};
#define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
@@ -167,6 +174,11 @@ ccp_ReportStatus(struct cmdargs const *arg)
command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1]));
prompt_Printf(arg->prompt, " DEFLATE24: %s\n",
command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24]));
+#ifdef HAVE_DES
+ prompt_Printf(arg->prompt, " MPPE: %s\n",
+ command_ShowNegval(ccp->cfg.neg[CCP_NEG_MPPE]));
+ prompt_Printf(arg->prompt, "Key Size = %d-bits\n", ccp->cfg.mppe.keybits);
+#endif
return 0;
}
@@ -196,6 +208,10 @@ ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l,
ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED;
ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED;
ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0;
+#ifdef HAVE_DES
+ ccp->cfg.mppe.keybits = 128;
+ ccp->cfg.neg[CCP_NEG_MPPE] = 0;
+#endif
ccp_Setup(ccp);
}
diff --git a/usr.sbin/ppp/ccp.h b/usr.sbin/ppp/ccp.h
index 72342dd..0dc1901 100644
--- a/usr.sbin/ppp/ccp.h
+++ b/usr.sbin/ppp/ccp.h
@@ -29,6 +29,7 @@
#define TY_HWPPC 16 /* Hewlett-Packard PPC */
#define TY_STAC 17 /* Stac Electronics LZS */
#define TY_MSPPC 18 /* Microsoft PPC */
+#define TY_MPPE 18 /* Microsoft PPE */
#define TY_GAND 19 /* Gandalf FZA */
#define TY_V42BIS 20 /* V.42bis compression */
#define TY_BSD 21 /* BSD LZW Compress */
@@ -38,7 +39,12 @@
#define CCP_NEG_DEFLATE 0
#define CCP_NEG_PRED1 1
#define CCP_NEG_DEFLATE24 2
+#ifdef HAVE_DES
+#define CCP_NEG_MPPE 3
+#define CCP_NEG_TOTAL 4
+#else
#define CCP_NEG_TOTAL 3
+#endif
struct mbuf;
struct link;
@@ -49,6 +55,11 @@ struct ccp_config {
int winsize;
} in, out;
} deflate;
+#ifdef HAVE_DES
+ struct {
+ int keybits;
+ } mppe;
+#endif
struct fsm_retry fsm; /* How often/frequently to resend requests */
unsigned neg[CCP_NEG_TOTAL];
};
diff --git a/usr.sbin/ppp/chap.c b/usr.sbin/ppp/chap.c
index 277b728..406931b 100644
--- a/usr.sbin/ppp/chap.c
+++ b/usr.sbin/ppp/chap.c
@@ -75,6 +75,7 @@
#include "datalink.h"
#ifdef HAVE_DES
#include "chap_ms.h"
+#include "mppe.h"
#endif
#include "id.h"
@@ -111,7 +112,7 @@ ChapOutput(struct physical *physical, u_int code, u_int id,
static char *
chap_BuildAnswer(char *name, char *key, u_char id, char *challenge, u_char type
#ifdef HAVE_DES
- , int lanman
+ , char *peerchallenge, char *authresponse, int lanman
#endif
)
{
@@ -167,6 +168,51 @@ chap_BuildAnswer(char *name, char *key, u_char id, char *challenge, u_char type
* ---- -------- ------------- ----- ------
* where only one of LANMan & NT digest are set.
*/
+ } else if (type == 0x81) {
+ char expkey[AUTHLEN << 2];
+ char pwdhash[CHAP81_HASH_LEN];
+ char pwdhashhash[CHAP81_HASH_LEN];
+ char *ntresponse;
+ int f;
+
+ if ((result = malloc(1 + nlen + CHAP81_RESPONSE_LEN)) == NULL)
+ return result;
+
+ memset(result, 0, 1 + nlen + CHAP81_RESPONSE_LEN);
+
+ digest = result;
+ *digest++ = CHAP81_RESPONSE_LEN; /* value size */
+
+ /* Copy our challenge */
+ memcpy(digest, peerchallenge + 1, CHAP81_CHALLENGE_LEN);
+
+ /* Expand password to Unicode XXX */
+ for (f = 0; f < klen; f++) {
+ expkey[2*f] = key[f];
+ expkey[2*f+1] = '\0';
+ }
+
+ ntresponse = digest + CHAP81_NTRESPONSE_OFF;
+
+ /* Get some needed hashes */
+ NtPasswordHash(expkey, klen * 2, pwdhash);
+ HashNtPasswordHash(pwdhash, pwdhashhash);
+
+ /* Generate NTRESPONSE to respond on challenge call */
+ GenerateNTResponse(challenge + 1, peerchallenge + 1, name, nlen,
+ expkey, klen * 2, ntresponse);
+
+ /* Generate MPPE MASTERKEY */
+ GetMasterKey(pwdhashhash, ntresponse, MPPE_MasterKey);
+
+ /* Generate AUTHRESPONSE to verify on auth success */
+ GenerateAuthenticatorResponse(expkey, klen * 2, ntresponse,
+ peerchallenge + 1, challenge + 1, name, nlen,
+ authresponse);
+
+ authresponse[CHAP81_AUTHRESPONSE_LEN] = 0;
+
+ memcpy(digest + CHAP81_RESPONSE_LEN, name, nlen);
} else
#endif
if ((result = malloc(nlen + 17)) != NULL) {
@@ -316,7 +362,7 @@ chap_Respond(struct chap *chap, char *name, char *key, u_char type
ans = chap_BuildAnswer(name, key, chap->auth.id, chap->challenge.peer, type
#ifdef HAVE_DES
- , lm
+ , chap->challenge.local, chap->authresponse, lm
#endif
);
@@ -421,7 +467,7 @@ chap_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
}
static void
-chap_Challenge(struct authinfo *authp)
+chap_ChallengeInit(struct authinfo *authp)
{
struct chap *chap = auth2chap(authp);
int len, i;
@@ -445,6 +491,8 @@ chap_Challenge(struct authinfo *authp)
#ifdef HAVE_DES
if (authp->physical->link.lcp.want_authtype == 0x80)
*cp++ = 8; /* MS does 8 byte callenges :-/ */
+ else if (authp->physical->link.lcp.want_authtype == 0x81)
+ *cp++ = 16; /* MS-CHAP-V2 does 16 bytes challenges */
else
#endif
*cp++ = random() % (CHAPCHALLENGELEN-16) + 16;
@@ -453,15 +501,48 @@ chap_Challenge(struct authinfo *authp)
}
memcpy(cp, authp->physical->dl->bundle->cfg.auth.name, len);
}
- ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id, chap->challenge.local,
- 1 + *chap->challenge.local + len, NULL);
+}
+
+static void
+chap_Challenge(struct authinfo *authp)
+{
+ struct chap *chap = auth2chap(authp);
+ int len;
+
+ log_Printf(LogDEBUG, "CHAP%02X: Challenge\n", authp->physical->link.lcp.want_authtype);
+
+ len = strlen(authp->physical->dl->bundle->cfg.auth.name);
+
+ /* Generate new local challenge value */
+ if (!*chap->challenge.local)
+ chap_ChallengeInit(authp);
+
+#ifdef HAVE_DES
+ if (authp->physical->link.lcp.want_authtype == 0x81)
+ ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id,
+ chap->challenge.local, 1 + *chap->challenge.local, NULL);
+ else
+#endif
+ ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id,
+ chap->challenge.local, 1 + *chap->challenge.local + len, NULL);
}
static void
chap_Success(struct authinfo *authp)
{
+ char *msg;
datalink_GotAuthname(authp->physical->dl, authp->in.name);
- ChapOutput(authp->physical, CHAP_SUCCESS, authp->id, "Welcome!!", 10, NULL);
+#ifdef HAVE_DES
+ if (authp->physical->link.lcp.want_authtype == 0x81) {
+ msg = auth2chap(authp)->authresponse;
+ MPPE_MasterKeyValid = 1;
+ } else
+#endif
+ msg = "Welcome!!";
+
+ ChapOutput(authp->physical, CHAP_SUCCESS, authp->id, msg, strlen(msg) + 1,
+ NULL);
+
authp->physical->link.lcp.auth_ineed = 0;
if (Enabled(authp->physical->dl->bundle, OPT_UTMP))
physical_Login(authp->physical, authp->in.name);
@@ -477,7 +558,28 @@ chap_Success(struct authinfo *authp)
static void
chap_Failure(struct authinfo *authp)
{
- ChapOutput(authp->physical, CHAP_FAILURE, authp->id, "Invalid!!", 9, NULL);
+#ifdef HAVE_DES
+ char buf[1024];
+#endif
+ char *msg;
+
+#ifdef HAVE_DES
+ if (authp->physical->link.lcp.want_authtype == 0x81) {
+ int i;
+
+ msg = buf;
+ msg += sprintf(buf, "E=691 R=0 C=");
+ for (i=0; i<16; i++)
+ msg += sprintf(msg, "%02X", *(auth2chap(authp)->challenge.local+1+i));
+
+ sprintf(msg, " V=3 M=Invalid!");
+ msg = buf;
+ } else
+#endif
+ msg = "Invalid!!";
+
+ ChapOutput(authp->physical, CHAP_FAILURE, authp->id, msg, strlen(msg) + 1,
+ NULL);
datalink_AuthNotOk(authp->physical->dl);
}
@@ -610,6 +712,9 @@ chap_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
lanman = p->link.lcp.his_authtype == 0x80 &&
((chap->NTRespSent && IsAccepted(p->link.lcp.cfg.chap80lm)) ||
!IsAccepted(p->link.lcp.cfg.chap80nt));
+
+ /* Generate local challenge value */
+ chap_ChallengeInit(&chap->auth);
#endif
break;
@@ -632,7 +737,8 @@ chap_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
ans[alen+1] = '\0';
bp = auth_ReadName(&chap->auth, bp, len);
#ifdef HAVE_DES
- lanman = alen == 49 && ans[alen] == 0;
+ lanman = p->link.lcp.want_authtype == 0x80 &&
+ alen == 49 && ans[alen] == 0;
#endif
break;
@@ -717,25 +823,39 @@ chap_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
if (key) {
char *myans;
#ifdef HAVE_DES
- if (lanman && !IsEnabled(p->link.lcp.cfg.chap80lm)) {
+ if (p->link.lcp.want_authtype == 0x80 &&
+ lanman && !IsEnabled(p->link.lcp.cfg.chap80lm)) {
log_Printf(LogPHASE, "Auth failure: LANMan not enabled\n");
if (chap_HaveAnotherGo(chap))
break;
key = NULL;
- } else if (!lanman && !IsEnabled(p->link.lcp.cfg.chap80nt) &&
- p->link.lcp.want_authtype == 0x80) {
+ } else if (p->link.lcp.want_authtype == 0x80 &&
+ !lanman && !IsEnabled(p->link.lcp.cfg.chap80nt)) {
log_Printf(LogPHASE, "Auth failure: mschap not enabled\n");
if (chap_HaveAnotherGo(chap))
break;
key = NULL;
+ } else if (p->link.lcp.want_authtype == 0x81 &&
+ !IsEnabled(p->link.lcp.cfg.chap81)) {
+ log_Printf(LogPHASE, "Auth failure: CHAP81 not enabled\n");
+ key = NULL;
} else
#endif
{
+#ifdef HAVE_DES
+ /* Get peer's challenge */
+ if (p->link.lcp.want_authtype == 0x81) {
+ chap->challenge.peer[0] = CHAP81_CHALLENGE_LEN;
+ memcpy(chap->challenge.peer + 1, ans + 1, CHAP81_CHALLENGE_LEN);
+ }
+#endif
+
myans = chap_BuildAnswer(name, key, chap->auth.id,
chap->challenge.local,
p->link.lcp.want_authtype
#ifdef HAVE_DES
- , lanman
+ , chap->challenge.peer,
+ chap->authresponse, lanman
#endif
);
if (myans == NULL)
@@ -764,13 +884,27 @@ chap_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
case CHAP_SUCCESS:
if (p->link.lcp.auth_iwait == PROTO_CHAP) {
p->link.lcp.auth_iwait = 0;
- if (p->link.lcp.auth_ineed == 0)
+ if (p->link.lcp.auth_ineed == 0) {
+#ifdef HAVE_DES
+ if (p->link.lcp.his_authtype == 0x81) {
+ if (strncmp(ans, chap->authresponse, 42)) {
+ datalink_AuthNotOk(p->dl);
+ log_Printf(LogDEBUG, "CHAP81: AuthenticatorResponse: (%s) != ans: (%s)\n", chap->authresponse, ans);
+
+ } else {
+ /* Successful login */
+ MPPE_MasterKeyValid = 1;
+ datalink_AuthOk(p->dl);
+ }
+ } else
+#endif
/*
* We've succeeded in our ``login''
* If we're not expecting the peer to authenticate (or he already
* has), proceed to network phase.
*/
datalink_AuthOk(p->dl);
+ }
}
break;
diff --git a/usr.sbin/ppp/chap.h b/usr.sbin/ppp/chap.h
index 7de61b4..edffc42 100644
--- a/usr.sbin/ppp/chap.h
+++ b/usr.sbin/ppp/chap.h
@@ -46,12 +46,14 @@ struct chap {
#ifdef HAVE_DES
unsigned NTRespSent : 1; /* Our last response */
int peertries;
+ u_char authresponse[CHAPAUTHRESPONSELEN]; /* CHAP 81 response */
#endif
};
#define descriptor2chap(d) \
((d)->type == CHAP_DESCRIPTOR ? (struct chap *)(d) : NULL)
-#define auth2chap(a) (struct chap *)((char *)a - (int)&((struct chap *)0)->auth)
+#define auth2chap(a) \
+ ((struct chap *)((char *)a - (int)&((struct chap *)0)->auth))
extern void chap_Init(struct chap *, struct physical *);
extern void chap_ReInit(struct chap *);
diff --git a/usr.sbin/ppp/chap_ms.c b/usr.sbin/ppp/chap_ms.c
index 4333aa1..c2892c4 100644
--- a/usr.sbin/ppp/chap_ms.c
+++ b/usr.sbin/ppp/chap_ms.c
@@ -31,10 +31,32 @@
#else
#include <des.h>
#endif
+#include <sha.h>
+#include <md4.h>
#include <string.h>
#include "chap_ms.h"
+/*
+ * Documentation & specifications:
+ *
+ * MS-CHAP (CHAP80) rfc2433
+ * MS-CHAP-V2 (CHAP81) rfc2759
+ * MPPE key management draft-ietf-pppext-mppe-keys-02.txt
+ */
+
+static char SHA1_Pad1[40] =
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static char SHA1_Pad2[40] =
+ {0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
+ 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
+ 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
+ 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2};
+
/* unused, for documentation only */
/* only NTResp is filled in for FreeBSD */
struct MS_ChapResponse {
@@ -95,6 +117,217 @@ ChallengeResponse(u_char *challenge, u_char *pwHash, u_char *response)
DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
}
+void
+NtPasswordHash(char *key, int keylen, char *hash) {
+ MD4_CTX MD4context;
+
+ MD4Init(&MD4context);
+ MD4Update(&MD4context, key, keylen);
+ MD4Final(hash, &MD4context);
+}
+
+void
+HashNtPasswordHash(char *hash, char *hashhash) {
+ MD4_CTX MD4context;
+
+ MD4Init(&MD4context);
+ MD4Update(&MD4context, hash, 16);
+ MD4Final(hashhash, &MD4context);
+}
+
+void
+ChallengeHash(char *PeerChallenge, char *AuthenticatorChallenge, char *UserName, int UserNameLen, char *Challenge) {
+ SHA_CTX Context;
+ char Digest[SHA_DIGEST_LENGTH];
+ char *Name;
+
+ Name = strrchr(UserName, '\\');
+ if(NULL == Name)
+ Name = UserName;
+ else
+ Name++;
+
+ SHA1_Init(&Context);
+
+ SHA1_Update(&Context, PeerChallenge, 16);
+ SHA1_Update(&Context, AuthenticatorChallenge, 16);
+ SHA1_Update(&Context, UserName, UserNameLen);
+
+ SHA1_Final(Digest, &Context);
+ memcpy(Challenge, Digest, 8);
+}
+
+void
+GenerateNTResponse(char *AuthenticatorChallenge, char *PeerChallenge, char *UserName, int UserNameLen, char *Password, int PasswordLen, char *Response) {
+ char Challenge[8];
+ char PasswordHash[16];
+
+ ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, UserNameLen,
+ Challenge);
+ NtPasswordHash(Password, PasswordLen, PasswordHash);
+ ChallengeResponse(Challenge, PasswordHash, Response);
+}
+
+void
+GenerateAuthenticatorResponse(char *Password, int PasswordLen, char *NTResponse, char *PeerChallenge, char *AuthenticatorChallenge, char *UserName, int UserNameLen, char *AuthenticatorResponse) {
+ SHA_CTX Context;
+ char PasswordHash[16];
+ char PasswordHashHash[16];
+ char Challenge[8];
+ u_char Digest[SHA_DIGEST_LENGTH];
+ int i;
+
+ /*
+ * "Magic" constants used in response generation
+ */
+ char Magic1[39] =
+ {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
+ 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
+ 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
+ 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74};
+
+
+ char Magic2[41] =
+ {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
+ 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
+ 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
+ 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
+ 0x6E};
+ /*
+ * Hash the password with MD4
+ */
+ NtPasswordHash(Password, PasswordLen, PasswordHash);
+ /*
+ * Now hash the hash
+ */
+ HashNtPasswordHash(PasswordHash, PasswordHashHash);
+
+ SHA1_Init(&Context);
+ SHA1_Update(&Context, PasswordHashHash, 16);
+ SHA1_Update(&Context, NTResponse, 24);
+ SHA1_Update(&Context, Magic1, 39);
+ SHA1_Final(Digest, &Context);
+ ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, UserNameLen,
+ Challenge);
+ SHA1_Init(&Context);
+ SHA1_Update(&Context, Digest, 20);
+ SHA1_Update(&Context, Challenge, 8);
+ SHA1_Update(&Context, Magic2, 41);
+
+ /*
+ * Encode the value of 'Digest' as "S=" followed by
+ * 40 ASCII hexadecimal digits and return it in
+ * AuthenticatorResponse.
+ * For example,
+ * "S=0123456789ABCDEF0123456789ABCDEF01234567"
+ */
+ AuthenticatorResponse[0] = 'S';
+ AuthenticatorResponse[1] = '=';
+ SHA1_End(&Context, AuthenticatorResponse + 2);
+ for (i=2; i<42; i++)
+ AuthenticatorResponse[i] = toupper(AuthenticatorResponse[i]);
+
+}
+
+void
+GetMasterKey(char *PasswordHashHash, char *NTResponse, char *MasterKey) {
+ char Digest[SHA_DIGEST_LENGTH];
+ SHA_CTX Context;
+ static char Magic1[27] =
+ {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
+ 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
+ 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79};
+
+ SHA1_Init(&Context);
+ SHA1_Update(&Context, PasswordHashHash, 16);
+ SHA1_Update(&Context, NTResponse, 24);
+ SHA1_Update(&Context, Magic1, 27);
+ SHA1_Final(Digest, &Context);
+ memcpy(MasterKey, Digest, 16);
+}
+
+void
+GetAsymetricStartKey(char *MasterKey, char *SessionKey, int SessionKeyLength, int IsSend, int IsServer) {
+ char Digest[SHA_DIGEST_LENGTH];
+ SHA_CTX Context;
+ char *s;
+
+ static char Magic2[84] =
+ {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
+ 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
+ 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
+ 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
+ 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
+ 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
+ 0x6b, 0x65, 0x79, 0x2e};
+
+ static char Magic3[84] =
+ {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
+ 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
+ 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
+ 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
+ 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
+ 0x6b, 0x65, 0x79, 0x2e};
+
+ if (IsSend) {
+ if (IsServer) {
+ s = Magic3;
+ } else {
+ s = Magic2;
+ }
+ } else {
+ if (IsServer) {
+ s = Magic2;
+ } else {
+ s = Magic3;
+ }
+ }
+
+ SHA1_Init(&Context);
+ SHA1_Update(&Context, MasterKey, 16);
+ SHA1_Update(&Context, SHA1_Pad1, 40);
+ SHA1_Update(&Context, s, 84);
+ SHA1_Update(&Context, SHA1_Pad2, 40);
+ SHA1_Final(Digest, &Context);
+
+ memcpy(SessionKey, Digest, SessionKeyLength);
+}
+
+void
+GetNewKeyFromSHA(char *StartKey, char *SessionKey, long SessionKeyLength, char *InterimKey) {
+ SHA_CTX Context;
+ char Digest[SHA_DIGEST_LENGTH];
+
+ SHA1_Init(&Context);
+ SHA1_Update(&Context, StartKey, SessionKeyLength);
+ SHA1_Update(&Context, SHA1_Pad1, 40);
+ SHA1_Update(&Context, SessionKey, SessionKeyLength);
+ SHA1_Update(&Context, SHA1_Pad2, 40);
+ SHA1_Final(Digest, &Context);
+
+ memcpy(InterimKey, Digest, SessionKeyLength);
+}
+
+void
+Get_Key(char *InitialSessionKey, char *CurrentSessionKey, int LengthOfDesiredKey) {
+ SHA_CTX Context;
+ char Digest[SHA_DIGEST_LENGTH];
+
+ SHA1_Init(&Context);
+ SHA1_Update(&Context, InitialSessionKey, LengthOfDesiredKey);
+ SHA1_Update(&Context, SHA1_Pad1, 40);
+ SHA1_Update(&Context, CurrentSessionKey, LengthOfDesiredKey);
+ SHA1_Update(&Context, SHA1_Pad2, 40);
+ SHA1_Final(Digest, &Context);
+
+ memcpy(CurrentSessionKey, Digest, LengthOfDesiredKey);
+}
+
/* passwordHash 16-bytes MD4 hashed password
challenge 8-bytes peer CHAP challenge
since passwordHash is in a 24-byte buffer, response is written in there */
diff --git a/usr.sbin/ppp/chap_ms.h b/usr.sbin/ppp/chap_ms.h
index 5bf0f78..36b3c38 100644
--- a/usr.sbin/ppp/chap_ms.h
+++ b/usr.sbin/ppp/chap_ms.h
@@ -26,7 +26,21 @@
#define MAX_NT_PASSWORD 256
/* Don't rely on sizeof(MS_ChapResponse) in case of struct padding */
-#define MS_CHAP_RESPONSE_LEN 49
+#define MS_CHAP_RESPONSE_LEN 49
+#define CHAP81_RESPONSE_LEN 49
+#define CHAP81_NTRESPONSE_LEN 24
+#define CHAP81_NTRESPONSE_OFF 24
+#define CHAP81_HASH_LEN 16
+#define CHAP81_AUTHRESPONSE_LEN 42
+#define CHAP81_CHALLENGE_LEN 16
extern void mschap_NT(char *, char *);
extern void mschap_LANMan(char *, char *, char *);
+extern void GenerateNTResponse(char *, char *, char *, int, char *, int , char *);
+extern void HashNtPasswordHash(char *, char *);
+extern void NtPasswordHash(char *, int, char *);
+extern void ChallengeHash(char *, char *, char *UserName, int, char *);
+extern void GenerateAuthenticatorResponse(char *, int, char *, char *, char *, char *, int, char *);
+extern void GetAsymetricStartKey(char *, char *, int, int, int);
+extern void GetMasterKey(char *, char *, char *);
+extern void GetNewKeyFromSHA(char *, char *, long, char *);
diff --git a/usr.sbin/ppp/command.c b/usr.sbin/ppp/command.c
index 6024e1e..62a80e2 100644
--- a/usr.sbin/ppp/command.c
+++ b/usr.sbin/ppp/command.c
@@ -127,6 +127,7 @@
#define VAR_URGENTPORTS 33
#define VAR_LOGOUT 34
#define VAR_IFQUEUE 35
+#define VAR_KEYBITS 36
/* ``accept|deny|disable|enable'' masks */
#define NEG_HISMASK (1)
@@ -147,6 +148,8 @@
#define NEG_PROTOCOMP 51
#define NEG_SHORTSEQ 52
#define NEG_VJCOMP 53
+#define NEG_MPPE 54
+#define NEG_CHAP81 55
const char Version[] = "2.27";
@@ -1574,6 +1577,24 @@ SetVariable(struct cmdargs const *arg)
}
break;
+#ifdef HAVE_DES
+ case VAR_KEYBITS:
+ if (arg->argc > arg->argn) {
+ l->ccp.cfg.mppe.keybits = atoi(arg->argv[arg->argn]);
+ if (l->ccp.cfg.mppe.keybits != 40 &&
+ l->ccp.cfg.mppe.keybits != 56 &&
+ l->ccp.cfg.mppe.keybits != 128 ) {
+ log_Printf(LogWARN, "%d: Invalid bits number\n",
+ l->ccp.cfg.mppe.keybits);
+ l->ccp.cfg.mppe.keybits = 40;
+ }
+ } else {
+ err = "No bits number pecified\n";
+ log_Printf(LogWARN, err);
+ }
+ break;
+#endif
+
case VAR_DEVICE:
physical_SetDeviceList(cx->physical, arg->argc - arg->argn,
arg->argv + arg->argn);
@@ -1968,6 +1989,11 @@ static struct cmdtab const SetCommands[] = {
{"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
"deflate window sizes", "set deflate out-winsize in-winsize",
(const void *) VAR_WINSIZE},
+#ifdef HAVE_DES
+ {"mppe", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
+ "MPPE key size", "set mppe {40|56|128}",
+ (const void *) VAR_KEYBITS},
+#endif
{"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX,
"physical device name", "set device|line device-name[,device-name]",
(const void *) VAR_DEVICE},
@@ -2414,6 +2440,14 @@ NegotiateSet(struct cmdargs const *arg)
cx->physical->link.lcp.cfg.chap80lm &= keep;
cx->physical->link.lcp.cfg.chap80lm |= add;
break;
+ case NEG_CHAP81:
+ cx->physical->link.lcp.cfg.chap81 &= keep;
+ cx->physical->link.lcp.cfg.chap81 |= add;
+ break;
+ case NEG_MPPE:
+ l->ccp.cfg.neg[CCP_NEG_MPPE] &= keep;
+ l->ccp.cfg.neg[CCP_NEG_MPPE] |= add;
+ break;
#endif
case NEG_DEFLATE:
l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
@@ -2517,6 +2551,12 @@ static struct cmdtab const NegotiateCommands[] = {
{"LANMan", "chap80lm", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
"Microsoft (NT) CHAP", "accept|deny|disable|enable",
(const void *)NEG_CHAP80LM},
+ {"mschapv2", "chap81", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
+ "Microsoft CHAP v2", "accept|deny|disable|enable",
+ (const void *)NEG_CHAP81},
+ {"mppe", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
+ "MPPE encryption", "accept|deny|disable|enable",
+ (const void *)NEG_MPPE},
#endif
{"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
"Deflate compression", "accept|deny|disable|enable",
diff --git a/usr.sbin/ppp/defs.h b/usr.sbin/ppp/defs.h
index aee5d63..2e5fb41 100644
--- a/usr.sbin/ppp/defs.h
+++ b/usr.sbin/ppp/defs.h
@@ -49,6 +49,7 @@
#define AUTHLEN 100 /* Size of authname/authkey */
#define CHAPDIGESTLEN 100 /* Maximum chap digest */
#define CHAPCHALLENGELEN 48 /* Maximum chap challenge */
+#define CHAPAUTHRESPONSELEN 48 /* Maximum chap authresponse (chap81) */
#define MAXARGS 40 /* How many args per config line */
#define NCP_IDLE_TIMEOUT 180 /* Drop all links */
#define CHOKED_TIMEOUT 120 /* Delete queued packets w/ blocked tun */
diff --git a/usr.sbin/ppp/lcp.c b/usr.sbin/ppp/lcp.c
index b2b56e0..096b59b 100644
--- a/usr.sbin/ppp/lcp.c
+++ b/usr.sbin/ppp/lcp.c
@@ -193,6 +193,8 @@ lcp_ReportStatus(struct cmdargs const *arg)
command_ShowNegval(lcp->cfg.chap80nt));
prompt_Printf(arg->prompt, " LANMan = %s\n",
command_ShowNegval(lcp->cfg.chap80lm));
+ prompt_Printf(arg->prompt, " CHAP81 = %s\n",
+ command_ShowNegval(lcp->cfg.chap81));
#endif
prompt_Printf(arg->prompt, " LQR = %s\n",
command_ShowNegval(lcp->cfg.lqr));
@@ -244,6 +246,7 @@ lcp_Init(struct lcp *lcp, struct bundle *bundle, struct link *l,
#ifdef HAVE_DES
lcp->cfg.chap80nt = NEG_ACCEPTED;
lcp->cfg.chap80lm = NEG_ACCEPTED;
+ lcp->cfg.chap81 = 0;
#endif
lcp->cfg.lqr = NEG_ACCEPTED;
lcp->cfg.pap = NEG_ACCEPTED;
@@ -292,6 +295,9 @@ lcp_Setup(struct lcp *lcp, int openmode)
IsEnabled(lcp->cfg.chap80lm)) {
lcp->want_auth = PROTO_CHAP;
lcp->want_authtype = 0x80;
+ } else if (IsEnabled(lcp->cfg.chap81)) {
+ lcp->want_auth = PROTO_CHAP;
+ lcp->want_authtype = 0x81;
#endif
} else if (IsEnabled(lcp->cfg.pap)) {
lcp->want_auth = PROTO_PAP;
@@ -733,6 +739,12 @@ LcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
*dec->nakend++ = (unsigned char) (PROTO_CHAP >> 8);
*dec->nakend++ = (unsigned char) PROTO_CHAP;
*dec->nakend++ = 0x80;
+ } else if (IsAccepted(lcp->cfg.chap81)) {
+ *dec->nakend++ = *cp;
+ *dec->nakend++ = 5;
+ *dec->nakend++ = (unsigned char) (PROTO_CHAP >> 8);
+ *dec->nakend++ = (unsigned char) PROTO_CHAP;
+ *dec->nakend++ = 0x81;
#endif
} else
goto reqreject;
@@ -747,6 +759,7 @@ LcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
#ifdef HAVE_DES
|| (cp[4] == 0x80 && (IsAccepted(lcp->cfg.chap80nt) ||
(IsAccepted(lcp->cfg.chap80lm))))
+ || (cp[4] == 0x81 && IsAccepted(lcp->cfg.chap81))
#endif
) {
lcp->his_auth = proto;
@@ -755,9 +768,11 @@ LcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
dec->ackend += length;
} else {
#ifndef HAVE_DES
- if (cp[4] == 0x80)
+ if (cp[4] == 0x80) {
log_Printf(LogWARN, "CHAP 0x80 not available without DES\n");
- else
+ } else if (cp[4] == 0x81) {
+ log_Printf(LogWARN, "CHAP 0x81 not available without DES\n");
+ } else
#endif
if (cp[4] != 0x05)
log_Printf(LogWARN, "%s not supported\n",
@@ -777,6 +792,12 @@ LcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
*dec->nakend++ = (unsigned char) (PROTO_CHAP >> 8);
*dec->nakend++ = (unsigned char) PROTO_CHAP;
*dec->nakend++ = 0x80;
+ } else if (IsAccepted(lcp->cfg.chap81)) {
+ *dec->nakend++ = *cp;
+ *dec->nakend++ = 5;
+ *dec->nakend++ = (unsigned char) (PROTO_CHAP >> 8);
+ *dec->nakend++ = (unsigned char) PROTO_CHAP;
+ *dec->nakend++ = 0x81;
#endif
} else if (IsAccepted(lcp->cfg.pap)) {
*dec->nakend++ = *cp;
@@ -816,18 +837,24 @@ LcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
IsEnabled(lcp->cfg.chap80lm))) {
lcp->want_auth = PROTO_CHAP;
lcp->want_authtype = 0x80;
+ } else if (cp[4] == 0x81 && IsEnabled(lcp->cfg.chap81)) {
+ lcp->want_auth = PROTO_CHAP;
+ lcp->want_authtype = 0x81;
#endif
} else {
#ifndef HAVE_DES
- if (cp[4] == 0x80)
+ if (cp[4] == 0x80) {
log_Printf(LogLCP, "Peer will only send MSCHAP (not available"
" without DES)\n");
- else
+ } else if (cp[4] == 0x81) {
+ log_Printf(LogLCP, "Peer will only send MSCHAPV2 (not available"
+ " without DES)\n");
+ } else
#endif
log_Printf(LogLCP, "Peer will only send %s (not %s)\n",
Auth2Nam(PROTO_CHAP, cp[4]),
#ifdef HAVE_DES
- cp[4] == 0x80 ? "configured" :
+ (cp[4] == 0x80 || cp[4] == 0x81) ? "configured" :
#endif
"supported");
lcp->his_reject |= (1 << type);
diff --git a/usr.sbin/ppp/lcp.h b/usr.sbin/ppp/lcp.h
index 5c6d1bb..93eef4d 100644
--- a/usr.sbin/ppp/lcp.h
+++ b/usr.sbin/ppp/lcp.h
@@ -83,6 +83,7 @@ struct lcp {
#ifdef HAVE_DES
unsigned chap80nt : 2; /* Microsoft (NT) CHAP */
unsigned chap80lm : 2; /* Microsoft (LANMan) CHAP */
+ unsigned chap81 : 2; /* Microsoft CHAP v2 */
#endif
unsigned lqr : 2; /* Link Quality Report */
unsigned pap : 2; /* Password Authentication protocol */
diff --git a/usr.sbin/ppp/mppe.c b/usr.sbin/ppp/mppe.c
new file mode 100644
index 0000000..0257d2f
--- /dev/null
+++ b/usr.sbin/ppp/mppe.c
@@ -0,0 +1,422 @@
+/*-
+ * Copyright (c) 2000 Semen Ustimenko <semenu@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <sha.h>
+#include <openssl/rc4.h>
+
+#include "defs.h"
+#include "mbuf.h"
+#include "log.h"
+#include "timer.h"
+#include "fsm.h"
+#include "lqr.h"
+#include "hdlc.h"
+#include "lcp.h"
+#include "ccp.h"
+#include "chap_ms.h"
+#include "mppe.h"
+
+/*
+ * Documentation:
+ *
+ * draft-ietf-pppext-mppe-04.txt
+ * draft-ietf-pppext-mppe-keys-02.txt
+ */
+
+struct mppe_state {
+ int cohnum;
+ int keylen; /* 8 or 16 bytes */
+ int keybits; /* 40, 56 or 128 bits */
+ char sesskey[MPPE_KEY_LEN];
+ char mastkey[MPPE_KEY_LEN];
+ RC4_KEY rc4key;
+};
+
+int MPPE_MasterKeyValid = 0;
+char MPPE_MasterKey[MPPE_KEY_LEN];
+
+static void
+MPPEResetOutput(void *v)
+{
+ log_Printf(LogCCP, "MPPE: Output channel reset\n");
+}
+
+void
+MPPEReduceSessionKey(struct mppe_state *mp) {
+ switch(mp->keybits) {
+ case 40:
+ mp->sesskey[2] = 0x9e;
+ mp->sesskey[1] = 0x26;
+ case 56:
+ mp->sesskey[0] = 0xd1;
+ case 128:
+ }
+}
+
+void
+MPPEKeyChange(struct mppe_state *mp) {
+ char InterimKey[MPPE_KEY_LEN];
+ RC4_KEY RC4Key;
+
+ GetNewKeyFromSHA(mp->mastkey, mp->sesskey, mp->keylen, InterimKey);
+ RC4_set_key(&RC4Key, mp->keylen, InterimKey);
+ RC4(&RC4Key, mp->keylen, InterimKey, mp->sesskey);
+
+ MPPEReduceSessionKey(mp);
+}
+
+static struct mbuf *
+MPPEOutput(void *v, struct ccp *ccp, struct link *l, int pri, u_short *proto,
+ struct mbuf *mp)
+{
+ struct mppe_state *mop = (struct mppe_state *)v;
+ struct mbuf *mo;
+ u_short nproto;
+ int ilen;
+ char *rp;
+
+ log_Printf(LogCCP, "MPPE: Output\n");
+
+ ilen = m_length(mp);
+
+ log_Printf(LogDEBUG, "MPPE: Output: Proto %02x (%d bytes)\n", *proto, ilen);
+ if (*proto < 0x21 && *proto > 0xFA) {
+ log_Printf(LogDEBUG, "MPPE: Output: Not encrypting\n");
+ return mp;
+ }
+
+ log_DumpBp(LogDEBUG, "MPPE: Output: Encrypt packet:", mp);
+
+ /* Get mbuf for prefixes */
+ mo = m_get(4, MB_CCPOUT);
+ mo->m_next = mp;
+
+ /* Init RC4 keys */
+ RC4_set_key(&mop->rc4key, mop->keylen, mop->sesskey);
+
+ /* Set MPPE packet prefix */
+ rp = MBUF_CTOP(mo);
+ *(u_short *)rp = htons(0x9000 | mop->cohnum);
+
+ /* Save encrypted protocol number */
+ nproto = htons(*proto);
+ RC4(&mop->rc4key, 2, (char *)&nproto, rp + 2);
+
+ /* Encrypt main packet */
+ rp = MBUF_CTOP(mp);
+ RC4(&mop->rc4key, ilen, rp, rp);
+
+ /* Rotate keys */
+ MPPEKeyChange(mop);
+ mop->cohnum ++; mop->cohnum &= 0xFFF;
+
+ /* Chage protocol number */
+ *proto = ccp_Proto(ccp);
+
+ log_Printf(LogDEBUG, "MPPE: Output: Encrypted: Proto %02x (%d bytes)\n", *proto, m_length(mo));
+
+ return mo;
+}
+
+static void
+MPPEResetInput(void *v)
+{
+ log_Printf(LogCCP, "MPPE: Input channel reset\n");
+}
+
+static struct mbuf *
+MPPEInput(void *v, struct ccp *ccp, u_short *proto, struct mbuf *mp)
+{
+ struct mppe_state *mip = (struct mppe_state *)v;
+ u_short prefix;
+ char *rp;
+ int ilen;
+
+ log_Printf(LogCCP, "MPPE: Input\n");
+
+ ilen = m_length(mp);
+
+ log_Printf(LogDEBUG, "MPPE: Input: Proto %02x (%d bytes)\n", *proto, ilen);
+
+ log_DumpBp(LogDEBUG, "MPPE: Input: Packet:", mp);
+
+ mp = mbuf_Read(mp, &prefix, 2);
+ prefix = ntohs(prefix);
+ if ((prefix & 0xF000) != 0x9000) {
+ log_Printf(LogERROR, "MPPE: Input: Invalid packet\n");
+ m_freem(mp);
+ return NULL;
+ }
+
+ prefix &= 0xFFF;
+ while (prefix != mip->cohnum) {
+ MPPEKeyChange(mip);
+ mip->cohnum ++; mip->cohnum &= 0xFFF;
+ }
+
+ RC4_set_key(&mip->rc4key, mip->keylen, mip->sesskey);
+
+ mp = mbuf_Read(mp, proto, 2);
+ RC4(&mip->rc4key, 2, (char *)proto, (char *)proto);
+ *proto = ntohs(*proto);
+
+ rp = MBUF_CTOP(mp);
+ RC4(&mip->rc4key, m_length(mp), rp, rp);
+
+ log_Printf(LogDEBUG, "MPPE: Input: Decrypted: Proto %02x (%d bytes)\n", *proto, m_length(mp));
+
+ log_DumpBp(LogDEBUG, "MPPE: Input: Decrypted: Packet:", mp);
+
+ return mp;
+}
+
+static void
+MPPEDictSetup(void *v, struct ccp *ccp, u_short proto, struct mbuf *mi)
+{
+ log_Printf(LogCCP, "MPPE: DictSetup\n");
+}
+
+static const char *
+MPPEDispOpts(struct lcp_opt *o)
+{
+ static char buf[32];
+ sprintf(buf, "value 0x%08x", (int)ntohl(*(u_int32_t *)(o->data)));
+ return buf;
+}
+
+static void
+MPPEInitOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg)
+{
+ u_long val;
+
+ o->len = 6;
+
+ log_Printf(LogCCP, "MPPE: InitOptsOutput\n");
+
+ if (!MPPE_MasterKeyValid) {
+ log_Printf(LogWARN, "MPPE: MasterKey is invalid, MPPE is capable only with CHAP81 authentication\n");
+ *(u_int32_t *)o->data = htonl(0x0);
+ return;
+ }
+
+ val = 0x1000000;
+ switch(cfg->mppe.keybits) {
+ case 128:
+ val |= 0x40; break;
+ case 56:
+ val |= 0x80; break;
+ case 40:
+ val |= 0x20; break;
+ }
+ *(u_int32_t *)o->data = htonl(val);
+}
+
+static int
+MPPESetOptsOutput(struct lcp_opt *o)
+{
+ u_long *p = (u_long *)(o->data);
+ u_long val = ntohl(*p);
+
+ log_Printf(LogCCP, "MPPE: SetOptsOutput\n");
+
+ if (!MPPE_MasterKeyValid) {
+ if (*p != 0x0) {
+ *p = 0x0;
+ return MODE_NAK;
+ } else {
+ return MODE_ACK;
+ }
+ }
+
+ if (val == 0x01000020 ||
+ val == 0x01000040 ||
+ val == 0x01000080)
+ return MODE_ACK;
+
+ return MODE_NAK;
+}
+
+static int
+MPPESetOptsInput(struct lcp_opt *o, const struct ccp_config *cfg)
+{
+ u_long *p = (u_long *)(o->data);
+ u_long val = ntohl(*p);
+ u_long mval;
+
+ log_Printf(LogCCP, "MPPE: SetOptsInput\n");
+
+ if (!MPPE_MasterKeyValid) {
+ if (*p != 0x0) {
+ *p = 0x0;
+ return MODE_NAK;
+ } else {
+ return MODE_ACK;
+ }
+ }
+
+ mval = 0x01000000;
+ switch(cfg->mppe.keybits) {
+ case 128:
+ mval |= 0x40; break;
+ case 56:
+ mval |= 0x80; break;
+ case 40:
+ mval |= 0x20; break;
+ }
+
+ if (val == mval)
+ return MODE_ACK;
+
+ *p = htonl(mval);
+
+ return MODE_NAK;
+}
+
+static void *
+MPPEInitInput(struct lcp_opt *o)
+{
+ struct mppe_state *mip;
+ u_int32_t val = ntohl(*(unsigned long *)o->data);
+
+ log_Printf(LogCCP, "MPPE: InitInput\n");
+
+ if (!MPPE_MasterKeyValid) {
+ log_Printf(LogERROR, "MPPE: InitInput: MasterKey is invalid!!!!\n");
+ return NULL;
+ }
+
+ mip = malloc(sizeof(*mip));
+ memset(mip, 0, sizeof(*mip));
+
+ if (val & 0x20) { /* 40-bits */
+ mip->keylen = 8;
+ mip->keybits = 40;
+ } else if (val & 0x80) { /* 56-bits */
+ mip->keylen = 8;
+ mip->keybits = 56;
+ } else { /* 128-bits */
+ mip->keylen = 16;
+ mip->keybits = 128;
+ }
+
+ log_Printf(LogDEBUG, "MPPE: InitInput: %d-bits\n", mip->keybits);
+
+ GetAsymetricStartKey(MPPE_MasterKey, mip->mastkey, mip->keylen, 0, 0);
+ GetNewKeyFromSHA(mip->mastkey, mip->mastkey, mip->keylen, mip->sesskey);
+
+ MPPEReduceSessionKey(mip);
+
+ MPPEKeyChange(mip);
+
+ mip->cohnum = 0;
+
+ return mip;
+}
+
+static void *
+MPPEInitOutput(struct lcp_opt *o)
+{
+ struct mppe_state *mop;
+ u_int32_t val = ntohl(*(unsigned long *)o->data);
+
+ log_Printf(LogCCP, "MPPE: InitOutput\n");
+
+ if (!MPPE_MasterKeyValid) {
+ log_Printf(LogERROR, "MPPE: InitOutput: MasterKey is invalid!!!!\n");
+ return NULL;
+ }
+
+ mop = malloc(sizeof(*mop));
+ memset(mop, 0, sizeof(*mop));
+
+ if (val & 0x20) { /* 40-bits */
+ mop->keylen = 8;
+ mop->keybits = 40;
+ } else if (val & 0x80) { /* 56-bits */
+ mop->keylen = 8;
+ mop->keybits = 56;
+ } else { /* 128-bits */
+ mop->keylen = 16;
+ mop->keybits = 128;
+ }
+
+ log_Printf(LogDEBUG, "MPPE: InitOutput: %d-bits\n", mop->keybits);
+
+ GetAsymetricStartKey(MPPE_MasterKey, mop->mastkey, mop->keylen, 1, 0);
+ GetNewKeyFromSHA(mop->mastkey, mop->mastkey, mop->keylen, mop->sesskey);
+
+ MPPEReduceSessionKey(mop);
+
+ MPPEKeyChange(mop);
+
+ mop->cohnum = 0;
+
+ return mop;
+}
+
+static void
+MPPETermInput(void *v)
+{
+ log_Printf(LogCCP, "MPPE: TermInput\n");
+ free(v);
+}
+
+static void
+MPPETermOutput(void *v)
+{
+ log_Printf(LogCCP, "MPPE: TermOutput\n");
+ free(v);
+}
+
+const struct ccp_algorithm MPPEAlgorithm = {
+ TY_MPPE,
+ CCP_NEG_MPPE,
+ MPPEDispOpts,
+ {
+ MPPESetOptsInput,
+ MPPEInitInput,
+ MPPETermInput,
+ MPPEResetInput,
+ MPPEInput,
+ MPPEDictSetup
+ },
+ {
+ MPPEInitOptsOutput,
+ MPPESetOptsOutput,
+ MPPEInitOutput,
+ MPPETermOutput,
+ MPPEResetOutput,
+ MPPEOutput
+ },
+};
+
diff --git a/usr.sbin/ppp/mppe.h b/usr.sbin/ppp/mppe.h
new file mode 100644
index 0000000..ee54cdb
--- /dev/null
+++ b/usr.sbin/ppp/mppe.h
@@ -0,0 +1,32 @@
+/*-
+ * Copyright (c) 2000 Semen Ustimenko <semenu@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#define MPPE_KEY_LEN 16
+extern const struct ccp_algorithm MPPEAlgorithm;
+extern int MPPE_MasterKeyValid;
+extern char MPPE_MasterKey[];
diff --git a/usr.sbin/ppp/ppp.8 b/usr.sbin/ppp/ppp.8
index 33cb29f..90d99f8 100644
--- a/usr.sbin/ppp/ppp.8
+++ b/usr.sbin/ppp/ppp.8
@@ -243,7 +243,7 @@ In direct mode,
acts as server which accepts incoming
.Em PPP
connections on stdin/stdout.
-.It Supports PAP and CHAP (rfc 1994) authentication.
+.It Supports PAP and CHAP (rfc 1994, 2433 and 2759) authentication.
With PAP or CHAP, it is possible to skip the Unix style
.Xr login 1
procedure, and use the
@@ -353,6 +353,14 @@ It is possible to configure
.Nm
to open more than one physical connection to the peer, combining the
bandwidth of all links for better throughput.
+.It Supports MPPE (draft-ietf-pppext-mppe)
+MPPE is Microsoft Point to Point Encryption scheme. It is possible to configure
+.Nm
+to participate in Microsoft's Windows VPN. For now,
+.Nm
+can only get encryption keys from CHAP 81 authentication.
+.Nm
+must be compiled with DES for MPPE to operate.
.El
.Sh PERMISSIONS
.Nm
@@ -2654,8 +2662,20 @@ level, and any appropriate
.Dq reconnect
values are honoured as if the peer were responsible for dropping the
connection.
+.It mppe
+Default: Disabled and Denied.
+This is Microsoft Point to Point Encryption scheme. MPPE key size can be
+40-, 56- and 128-bits. Refer to
+.Dq set mppe
+command.
+.It MSChapV2|chap81
+Default: Disabled and Denied.
+It is very similar to standard CHAP (type 0x05)
+except that it issues challenges of a fixed 16 bytes in length and uses a
+combination of MD4, SHA-1 and DES to encrypt the challenge rather than using the
+standard MD5 mechanism.
.It MSChap|chap80nt
-Default: Disabled and Accepted.
+Default: Disabled and Denied.
The use of this authentication protocol
is discouraged as it partially violates the authentication protocol by
implementing two different mechanisms (LANMan & NT) under the guise of
@@ -4738,6 +4758,8 @@ This will allow
to do the necessary address translations to enable the process that
triggers the connection to connect once the link is up despite the
peer assigning us a new (dynamic) IP address.
+.It set mppe {40|56|128}
+This option selects particular key length. Default is 128.
.It set mrru Op Ar value
Setting this option enables Multi-link PPP negotiations, also known as
Multi-link Protocol or MP.
diff --git a/usr.sbin/ppp/ppp.8.m4 b/usr.sbin/ppp/ppp.8.m4
index 33cb29f..90d99f8 100644
--- a/usr.sbin/ppp/ppp.8.m4
+++ b/usr.sbin/ppp/ppp.8.m4
@@ -243,7 +243,7 @@ In direct mode,
acts as server which accepts incoming
.Em PPP
connections on stdin/stdout.
-.It Supports PAP and CHAP (rfc 1994) authentication.
+.It Supports PAP and CHAP (rfc 1994, 2433 and 2759) authentication.
With PAP or CHAP, it is possible to skip the Unix style
.Xr login 1
procedure, and use the
@@ -353,6 +353,14 @@ It is possible to configure
.Nm
to open more than one physical connection to the peer, combining the
bandwidth of all links for better throughput.
+.It Supports MPPE (draft-ietf-pppext-mppe)
+MPPE is Microsoft Point to Point Encryption scheme. It is possible to configure
+.Nm
+to participate in Microsoft's Windows VPN. For now,
+.Nm
+can only get encryption keys from CHAP 81 authentication.
+.Nm
+must be compiled with DES for MPPE to operate.
.El
.Sh PERMISSIONS
.Nm
@@ -2654,8 +2662,20 @@ level, and any appropriate
.Dq reconnect
values are honoured as if the peer were responsible for dropping the
connection.
+.It mppe
+Default: Disabled and Denied.
+This is Microsoft Point to Point Encryption scheme. MPPE key size can be
+40-, 56- and 128-bits. Refer to
+.Dq set mppe
+command.
+.It MSChapV2|chap81
+Default: Disabled and Denied.
+It is very similar to standard CHAP (type 0x05)
+except that it issues challenges of a fixed 16 bytes in length and uses a
+combination of MD4, SHA-1 and DES to encrypt the challenge rather than using the
+standard MD5 mechanism.
.It MSChap|chap80nt
-Default: Disabled and Accepted.
+Default: Disabled and Denied.
The use of this authentication protocol
is discouraged as it partially violates the authentication protocol by
implementing two different mechanisms (LANMan & NT) under the guise of
@@ -4738,6 +4758,8 @@ This will allow
to do the necessary address translations to enable the process that
triggers the connection to connect once the link is up despite the
peer assigning us a new (dynamic) IP address.
+.It set mppe {40|56|128}
+This option selects particular key length. Default is 128.
.It set mrru Op Ar value
Setting this option enables Multi-link PPP negotiations, also known as
Multi-link Protocol or MP.
OpenPOWER on IntegriCloud