$NetBSD$

--- pppd/chap_ms.c.orig	Fri Aug 13 08:46:12 1999
+++ pppd/chap_ms.c	Wed Dec  8 14:52:48 1999
@@ -31,6 +31,14 @@
  *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
  */
 
+/*
+ * Mods by Tim Hockin, Cobalt Networks Inc. <thockin@cobaltnet.com> June 1999
+ *
+ * Cleanup, fixes and major reorganization.
+ * Migrated all MPPE code to mppe.c, shared crypto code to extra_crypto.c
+ *
+ */
+
 #define RCSID	"$Id: chap_ms.c,v 1.15 1999/08/13 06:46:12 paulus Exp $"
 
 #ifdef CHAPMS
@@ -49,11 +57,13 @@
 #include "pppd.h"
 #include "chap.h"
 #include "chap_ms.h"
-#include "md4.h"
-
-#ifndef USE_CRYPT
-#include <des.h>
+#include "sha.h"
+#include "fsm.h"
+#include "lcp.h"
+#ifdef MPPE
+#include "mppe.h"
 #endif
+#include "extra_crypto.h"
 
 static const char rcsid[] = RCSID;
 
@@ -65,21 +75,19 @@
 /* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
    in case this struct gets padded. */
 
+typedef struct {
+    u_char PeerChallenge[16];
+    u_char Reserved[8];
+    u_char NTResp[24];
+    u_char Flags;
+} MS_ChapResponse_v2;
 
 static void	ChallengeResponse __P((u_char *, u_char *, u_char *));
-static void	DesEncrypt __P((u_char *, u_char *, u_char *));
-static void	MakeKey __P((u_char *, u_char *));
-static u_char	Get7Bits __P((u_char *, int));
 static void	ChapMS_NT __P((char *, int, char *, int, MS_ChapResponse *));
 #ifdef MSLANMAN
 static void	ChapMS_LANMan __P((char *, int, char *, int, MS_ChapResponse *));
 #endif
 
-#ifdef USE_CRYPT
-static void	Expand __P((u_char *, u_char *));
-static void	Collapse __P((u_char *, u_char *));
-#endif
-
 #ifdef MSLANMAN
 bool	ms_lanman = 0;    	/* Use LanMan password instead of NT */
 			  	/* Has meaning only with MS-CHAP challenges */
@@ -110,142 +118,6 @@
 #endif
 }
 
-
-#ifdef USE_CRYPT
-static void
-DesEncrypt(clear, key, cipher)
-    u_char *clear;	/* IN  8 octets */
-    u_char *key;	/* IN  7 octets */
-    u_char *cipher;	/* OUT 8 octets */
-{
-    u_char des_key[8];
-    u_char crypt_key[66];
-    u_char des_input[66];
-
-    MakeKey(key, des_key);
-
-    Expand(des_key, crypt_key);
-    setkey(crypt_key);
-
-#if 0
-    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %.8B", clear));
-#endif
-
-    Expand(clear, des_input);
-    encrypt(des_input, 0);
-    Collapse(des_input, cipher);
-
-#if 0
-    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", cipher));
-#endif
-}
-
-#else /* USE_CRYPT */
-
-static void
-DesEncrypt(clear, key, cipher)
-    u_char *clear;	/* IN  8 octets */
-    u_char *key;	/* IN  7 octets */
-    u_char *cipher;	/* OUT 8 octets */
-{
-    des_cblock		des_key;
-    des_key_schedule	key_schedule;
-
-    MakeKey(key, des_key);
-
-    des_set_key(&des_key, key_schedule);
-
-#if 0
-    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %.8B", clear));
-#endif
-
-    des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
-
-#if 0
-    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", cipher));
-#endif
-}
-
-#endif /* USE_CRYPT */
-
-
-static u_char Get7Bits(input, startBit)
-    u_char *input;
-    int startBit;
-{
-    register unsigned int	word;
-
-    word  = (unsigned)input[startBit / 8] << 8;
-    word |= (unsigned)input[startBit / 8 + 1];
-
-    word >>= 15 - (startBit % 8 + 7);
-
-    return word & 0xFE;
-}
-
-#ifdef USE_CRYPT
-
-/* in == 8-byte string (expanded version of the 56-bit key)
- * out == 64-byte string where each byte is either 1 or 0
- * Note that the low-order "bit" is always ignored by by setkey()
- */
-static void Expand(in, out)
-    u_char *in;
-    u_char *out;
-{
-        int j, c;
-        int i;
-
-        for(i = 0; i < 64; in++){
-		c = *in;
-                for(j = 7; j >= 0; j--)
-                        *out++ = (c >> j) & 01;
-                i += 8;
-        }
-}
-
-/* The inverse of Expand
- */
-static void Collapse(in, out)
-    u_char *in;
-    u_char *out;
-{
-        int j;
-        int i;
-	unsigned int c;
-
-	for (i = 0; i < 64; i += 8, out++) {
-	    c = 0;
-	    for (j = 7; j >= 0; j--, in++)
-		c |= *in << j;
-	    *out = c & 0xff;
-	}
-}
-#endif
-
-static void MakeKey(key, des_key)
-    u_char *key;	/* IN  56 bit DES key missing parity bits */
-    u_char *des_key;	/* OUT 64 bit DES key with parity bits added */
-{
-    des_key[0] = Get7Bits(key,  0);
-    des_key[1] = Get7Bits(key,  7);
-    des_key[2] = Get7Bits(key, 14);
-    des_key[3] = Get7Bits(key, 21);
-    des_key[4] = Get7Bits(key, 28);
-    des_key[5] = Get7Bits(key, 35);
-    des_key[6] = Get7Bits(key, 42);
-    des_key[7] = Get7Bits(key, 49);
-
-#ifndef USE_CRYPT
-    des_set_odd_parity((des_cblock *)des_key);
-#endif
-
-#if 0
-    CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %.7B", key));
-    CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %.8B", des_key));
-#endif
-}
-
 static void
 ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, response)
     char *rchallenge;
@@ -254,34 +126,13 @@
     int secret_len;
     MS_ChapResponse    *response;
 {
-    int			i;
-#ifdef __NetBSD__
-    /* NetBSD uses the libc md4 routines which take bytes instead of bits */
-    int			mdlen = secret_len * 2;
-#else
-    int			mdlen = secret_len * 2 * 8;
-#endif
-    MD4_CTX		md4Context;
     u_char		hash[MD4_SIGNATURE_SIZE];
-    u_char		unicodePassword[MAX_NT_PASSWORD * 2];
-
-    /* Initialize the Unicode version of the secret (== password). */
-    /* This implicitly supports 8-bit ISO8859/1 characters. */
-    BZERO(unicodePassword, sizeof(unicodePassword));
-    for (i = 0; i < secret_len; i++)
-	unicodePassword[i * 2] = (u_char)secret[i];
-
-    MD4Init(&md4Context);
-    MD4Update(&md4Context, unicodePassword, mdlen);
-
-    MD4Final(hash, &md4Context); 	/* Tell MD4 we're done */
 
+    NtPasswordHash(secret, secret_len, hash);
     ChallengeResponse(rchallenge, hash, response->NTResp);
 }
 
 #ifdef MSLANMAN
-static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
-
 static void
 ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, response)
     char *rchallenge;
@@ -290,16 +141,9 @@
     int secret_len;
     MS_ChapResponse	*response;
 {
-    int			i;
-    u_char		UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
     u_char		PasswordHash[MD4_SIGNATURE_SIZE];
 
-    /* LANMan password is case insensitive */
-    BZERO(UcasePassword, sizeof(UcasePassword));
-    for (i = 0; i < secret_len; i++)
-       UcasePassword[i] = (u_char)toupper(secret[i]);
-    DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );
-    DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );
+    LmPasswordHash(secret, secret_len, PasswordHash);
     ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
 }
 #endif
@@ -331,8 +175,209 @@
     response.UseNT = 1;
 #endif
 
+#ifdef MPPE
+    mppe_gen_master_key(secret, secret_len, rchallenge);
+#endif
+    BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
+    cstate->resp_length = MS_CHAP_RESPONSE_LEN;
+}
+
+int
+ChapMS_Resp(cstate, secret, secret_len, remmd)
+    chap_state *cstate;
+    char *secret;
+    int secret_len;
+    u_char *remmd;
+{
+    MS_ChapResponse local;
+    MS_ChapResponse *response = (MS_ChapResponse *)remmd;
+    int i;
+
+    BZERO(&local, sizeof(response));
+
+    if(response->UseNT)
+    {
+      ChapMS_NT(cstate->challenge,cstate->chal_len, secret, secret_len, &local);
+      i = memcmp(local.NTResp, response->NTResp, sizeof(local.NTResp));
+
+#ifdef MPPE
+      if(i == 0)
+        mppe_gen_master_key(secret, secret_len, cstate->challenge);
+#endif
+      return(i);
+    }
+
+#ifdef MSLANMAN
+    ChapMS_LANMan(cstate->challenge, cstate->chal_len, secret, secret_len, 
+		&local);
+    if(memcmp(local.LANManResp, response->LANManResp, 
+	sizeof(local.LANManResp)) == 0) {
+#ifdef MPPE
+      mppe_gen_master_key(secret, secret_len, cstate->challenge);
+#endif
+      return(0);
+    }
+#endif /* MSLANMAN */
+    return(1);
+}
+
+void
+ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, Challenge)
+    char *PeerChallenge;
+    char *AuthenticatorChallenge;
+    char *UserName;
+    char *Challenge;
+{
+    SHA_CTX Context;
+    u_char Digest[SHA_DIGEST_LENGTH];
+    char *username;
+    
+    if((username = strrchr(UserName, '\\')) != (char *)NULL)
+      ++username;
+    else
+      username = UserName;
+    SHA1_Init(&Context);
+    SHA1_Update(&Context, PeerChallenge, 16);
+    SHA1_Update(&Context, AuthenticatorChallenge, 16);
+    SHA1_Update(&Context, username, strlen(username));
+    SHA1_Final(Digest, &Context);
+    BCOPY(Digest, Challenge, 8);
+}
+
+void
+ChapMS_v2(cstate, AuthenticatorChallenge, AuthenticatorChallengeLen, Password, PasswordLen)
+    chap_state *cstate;
+    char *AuthenticatorChallenge;
+    int AuthenticatorChallengeLen;
+    char *Password;
+    int PasswordLen;
+{
+    u_char Challenge[8];
+    u_char PasswordHash[MD4_SIGNATURE_SIZE];
+    MS_ChapResponse_v2 response;
+  
+    BZERO(&response, sizeof(response));
+    ChapGenChallenge(cstate);
+    BCOPY(cstate->challenge, response.PeerChallenge, 
+		sizeof(response.PeerChallenge));
+    ChallengeHash(response.PeerChallenge, AuthenticatorChallenge, 
+		cstate->resp_name, Challenge);
+    NtPasswordHash(Password, PasswordLen, PasswordHash);
+    ChallengeResponse(Challenge, PasswordHash, response.NTResp);
     BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
     cstate->resp_length = MS_CHAP_RESPONSE_LEN;
+#ifdef MPPE
+    mppe_gen_master_key_v2(Password, PasswordLen, response.NTResp, 0);
+#endif
+}
+
+int
+ChapMS_v2_Resp(cstate, Password, PasswordLen, remmd, UserName)
+    chap_state *cstate;
+    char *Password;
+    int PasswordLen;
+    u_char *remmd;
+    char *UserName;
+{
+    u_char Challenge[8];
+    u_char PasswordHash[MD4_SIGNATURE_SIZE];
+    MS_ChapResponse_v2 response, response1;
+    int i;
+  
+    BCOPY(remmd, &response, MS_CHAP_RESPONSE_LEN);
+    ChallengeHash(response.PeerChallenge,cstate->challenge,UserName,Challenge);
+    NtPasswordHash(Password, PasswordLen, PasswordHash);
+    ChallengeResponse(Challenge, PasswordHash, response1.NTResp);
+    i = memcmp(response.NTResp, response1.NTResp, sizeof(response.NTResp));
+#ifdef MPPE
+    if(i == 0)
+      mppe_gen_master_key_v2(Password, PasswordLen, response1.NTResp, 1);
+#endif
+    return(i);
+}
+
+void
+ChapMS_v2_Auth(cstate, Password, PasswordLen, remmd, UserName)
+    chap_state *cstate;
+    char *Password;
+    int  PasswordLen;
+    u_char *remmd;
+    char *UserName;
+{
+    u_char PasswordHash[MD4_SIGNATURE_SIZE];
+    u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
+    u_char Challenge[8];
+    static char Magic1[] = "Magic server to client signing constant";
+    static char Magic2[] = "Pad to make it do more than one iteration";
+
+    SHA_CTX Context;
+    u_char Digest[SHA_DIGEST_LENGTH];
+    MS_ChapResponse_v2 *response = (MS_ChapResponse_v2 *)remmd;
+    char   StrResponse[SHA_DIGEST_LENGTH * 2 + 3], *s;
+    int i;
+    static char HexDigs[] = "0123456789ABCDEF";
+    
+    NtPasswordHash(Password, PasswordLen, PasswordHash);
+    md4(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
+
+    SHA1_Init(&Context);
+    SHA1_Update(&Context, PasswordHashHash, 16);
+    SHA1_Update(&Context, response->NTResp, 24);
+    SHA1_Update(&Context, Magic1, sizeof(Magic1) - 1);
+    SHA1_Final(Digest, &Context);
+
+    ChallengeHash(response->PeerChallenge,cstate->challenge,UserName,Challenge);
+    
+    SHA1_Init(&Context);
+    SHA1_Update(&Context, Digest, SHA_DIGEST_LENGTH);
+    SHA1_Update(&Context, Challenge, 8);
+    SHA1_Update(&Context, Magic2, sizeof(Magic2) - 1);
+    SHA1_Final(Digest, &Context);
+    s = strcpy(StrResponse, "S=")+2;
+    for(i = 0; i < SHA_DIGEST_LENGTH; ++i) {
+      *s++ = HexDigs[Digest[i] >> 4];
+      *s++ = HexDigs[Digest[i] & 0x0F];
+    }
+    *s = '\0';
+    BCOPY(StrResponse, cstate->response, sizeof(StrResponse));
+    cstate->resp_length = sizeof(StrResponse) - 1;
+}
+
+/*
+ * functions called from config options
+ */
+int 
+reqchapms(char **argv)
+{
+    lcp_wantoptions[0].neg_chap = 1;
+    lcp_wantoptions[0].use_chapms = 1;
+    auth_required = 1;
+
+    return 1;
+}
+
+int 
+nochapms(char **argv)
+{
+    lcp_wantoptions[0].use_chapms = 0;
+    return 1;
+}
+
+int 
+reqchapms_v2(char **argv)
+{
+    lcp_wantoptions[0].neg_chap = 1;
+    lcp_wantoptions[0].use_chapms_v2 = 1;
+    auth_required = 1;
+
+    return 1;
+}
+
+int 
+nochapms_v2(char **argv)
+{
+    lcp_wantoptions[0].use_chapms_v2 = 0;
+    return 1;
 }
 
 #endif /* CHAPMS */
