From 06792c58d5296e43c29af28744e2aa418b29c02c Mon Sep 17 00:00:00 2001 From: brian Date: Mon, 30 Oct 2000 00:15:04 +0000 Subject: Add MPPE and MSChap v2 support (denied and disabled by default) Submitted by: Ustimenko Semen --- usr.sbin/ppp/Makefile | 2 +- usr.sbin/ppp/ccp.c | 18 ++- usr.sbin/ppp/ccp.h | 11 ++ usr.sbin/ppp/chap.c | 160 +++++++++++++++++-- usr.sbin/ppp/chap.h | 4 +- usr.sbin/ppp/chap_ms.c | 233 +++++++++++++++++++++++++++ usr.sbin/ppp/chap_ms.h | 16 +- usr.sbin/ppp/command.c | 40 +++++ usr.sbin/ppp/defs.h | 1 + usr.sbin/ppp/lcp.c | 37 ++++- usr.sbin/ppp/lcp.h | 1 + usr.sbin/ppp/mppe.c | 422 +++++++++++++++++++++++++++++++++++++++++++++++++ usr.sbin/ppp/mppe.h | 32 ++++ usr.sbin/ppp/ppp.8 | 26 ++- usr.sbin/ppp/ppp.8.m4 | 26 ++- 15 files changed, 1003 insertions(+), 26 deletions(-) create mode 100644 usr.sbin/ppp/mppe.c create mode 100644 usr.sbin/ppp/mppe.h (limited to 'usr.sbin') 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 #endif +#include +#include #include #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 + * 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 + +#include +#include +#include +#include +#include + +#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 + * 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. -- cgit v1.1