]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/chap_ms.c
pppd: Add support for EAP-MSCHAPv2 (client side) (#211)
[ppp.git] / pppd / chap_ms.c
index 05c6225a720612fe01afc43c917c59dd58a37ea3..e6b84f203fc3fc2f62ca2a471b17e11d8422e975 100644 (file)
@@ -74,7 +74,7 @@
  *
  */
 
-#define RCSID  "$Id: chap_ms.c,v 1.34 2004/11/15 22:13:26 paulus Exp $"
+#define RCSID  "$Id: chap_ms.c,v 1.38 2007/12/01 20:10:51 carlsonj Exp $"
 
 #ifdef CHAPMS
 
 #include "pppcrypt.h"
 #include "magic.h"
 
-static const char rcsid[] = RCSID;
 
 
-static void    ascii2unicode __P((char[], int, u_char[]));
-static void    NTPasswordHash __P((char *, int, u_char[MD4_SIGNATURE_SIZE]));
-static void    ChallengeResponse __P((u_char *, u_char *, u_char[24]));
-static void    ChapMS_NT __P((u_char *, char *, int, u_char[24]));
-static void    ChapMS2_NT __P((u_char *, u_char[16], char *, char *, int,
-                               u_char[24]));
+static void    ascii2unicode (char[], int, u_char[]);
+static void    NTPasswordHash (u_char *, int, u_char[MD4_SIGNATURE_SIZE]);
+static void    ChallengeResponse (u_char *, u_char *, u_char[24]);
+static void    ChapMS_NT (u_char *, char *, int, u_char[24]);
+static void    ChapMS2_NT (u_char *, u_char[16], char *, char *, int,
+                               u_char[24]);
 static void    GenerateAuthenticatorResponsePlain
-                       __P((char*, int, u_char[24], u_char[16], u_char *,
-                            char *, u_char[41]));
+                       (char*, int, u_char[24], u_char[16], u_char *,
+                        char *, u_char[41]);
 #ifdef MSLANMAN
-static void    ChapMS_LANMan __P((u_char *, char *, int, u_char *));
+static void    ChapMS_LANMan (u_char *, char *, int, u_char *);
 #endif
 
 #ifdef MPPE
-static void    Set_Start_Key __P((u_char *, char *, int));
-static void    SetMasterKeys __P((char *, int, u_char[24], int));
+static void    Set_Start_Key (u_char *, char *, int);
+static void    SetMasterKeys (char *, int, u_char[24], int);
 #endif
 
 #ifdef MSLANMAN
@@ -320,25 +319,90 @@ chapms_make_response(unsigned char *response, int id, char *our_name,
        ChapMS(challenge, secret, secret_len, response);
 }
 
+struct chapms2_response_cache_entry {
+       int id;
+       unsigned char challenge[16];
+       unsigned char response[MS_CHAP2_RESPONSE_LEN];
+       unsigned char auth_response[MS_AUTH_RESPONSE_LENGTH];
+};
+
+#define CHAPMS2_MAX_RESPONSE_CACHE_SIZE 10
+static struct chapms2_response_cache_entry
+    chapms2_response_cache[CHAPMS2_MAX_RESPONSE_CACHE_SIZE];
+static int chapms2_response_cache_next_index = 0;
+static int chapms2_response_cache_size = 0;
+
+static void
+chapms2_add_to_response_cache(int id, unsigned char *challenge,
+                             unsigned char *response,
+                             unsigned char *auth_response)
+{
+       int i = chapms2_response_cache_next_index;
+
+       chapms2_response_cache[i].id = id;
+       memcpy(chapms2_response_cache[i].challenge, challenge, 16);
+       memcpy(chapms2_response_cache[i].response, response,
+              MS_CHAP2_RESPONSE_LEN);
+       memcpy(chapms2_response_cache[i].auth_response,
+              auth_response, MS_AUTH_RESPONSE_LENGTH);
+       chapms2_response_cache_next_index =
+               (i + 1) % CHAPMS2_MAX_RESPONSE_CACHE_SIZE;
+       if (chapms2_response_cache_next_index > chapms2_response_cache_size)
+               chapms2_response_cache_size = chapms2_response_cache_next_index;
+       dbglog("added response cache entry %d", i);
+}
+
+static struct chapms2_response_cache_entry*
+chapms2_find_in_response_cache(int id, unsigned char *challenge,
+                     unsigned char *auth_response)
+{
+       int i;
+
+       for (i = 0; i < chapms2_response_cache_size; i++) {
+               if (id == chapms2_response_cache[i].id
+                   && (!challenge
+                       || memcmp(challenge,
+                                 chapms2_response_cache[i].challenge,
+                                 16) == 0)
+                   && (!auth_response
+                       || memcmp(auth_response,
+                                 chapms2_response_cache[i].auth_response,
+                                 MS_AUTH_RESPONSE_LENGTH) == 0)) {
+                       dbglog("response found in cache (entry %d)", i);
+                       return &chapms2_response_cache[i];
+               }
+       }
+       return NULL;  /* not found */
+}
+
 static void
 chapms2_make_response(unsigned char *response, int id, char *our_name,
                      unsigned char *challenge, char *secret, int secret_len,
                      unsigned char *private)
 {
+       const struct chapms2_response_cache_entry *cache_entry;
+       unsigned char auth_response[MS_AUTH_RESPONSE_LENGTH+1];
+
        challenge++;    /* skip length, should be 16 */
        *response++ = MS_CHAP2_RESPONSE_LEN;
+       cache_entry = chapms2_find_in_response_cache(id, challenge, NULL);
+       if (cache_entry) {
+               memcpy(response, cache_entry->response, MS_CHAP2_RESPONSE_LEN);
+               return;
+       }
        ChapMS2(challenge,
 #ifdef DEBUGMPPEKEY
                mschap2_peer_challenge,
 #else
                NULL,
 #endif
-               our_name, secret, secret_len, response, private,
+               our_name, secret, secret_len, response, auth_response,
                MS_CHAP2_AUTHENTICATEE);
+       chapms2_add_to_response_cache(id, challenge, response, auth_response);
 }
 
 static int
-chapms2_check_success(unsigned char *msg, int len, unsigned char *private)
+chapms2_check_success(int id, unsigned char *msg, int len)
 {
        if ((len < MS_AUTH_RESPONSE_LENGTH + 2) ||
            strncmp((char *)msg, "S=", 2) != 0) {
@@ -349,7 +413,7 @@ chapms2_check_success(unsigned char *msg, int len, unsigned char *private)
        msg += 2;
        len -= 2;
        if (len < MS_AUTH_RESPONSE_LENGTH
-           || memcmp(msg, private, MS_AUTH_RESPONSE_LENGTH)) {
+           || !chapms2_find_in_response_cache(id, NULL /* challenge */, msg)) {
                /* Authenticator Response did not match expected. */
                error("MS-CHAPv2 mutual authentication failed.");
                return 0;
@@ -359,6 +423,8 @@ chapms2_check_success(unsigned char *msg, int len, unsigned char *private)
        len -= MS_AUTH_RESPONSE_LENGTH;
        if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) {
                msg += 3; /* Eat the delimiter */
+       } else  if ((len >= 2) && !strncmp((char *)msg, "M=", 2)) {
+               msg += 2; /* Eat the delimiter */
        } else if (len) {
                /* Packet has extra text which does not begin " M=" */
                error("MS-CHAPv2 Success packet is badly formed.");
@@ -390,7 +456,7 @@ chapms_handle_failure(unsigned char *inp, int len)
         * chapms[2]_verify_response.
         */
        if (!strncmp(p, "E=", 2))
-               err = strtol(p, NULL, 10); /* Remember the error code. */
+               err = strtol(p+2, NULL, 10); /* Remember the error code. */
        else
                goto print_msg; /* Message is badly formatted. */
 
@@ -507,7 +573,7 @@ ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
 }
 
 static void
-NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
+NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
 {
 #ifdef __NetBSD__
     /* NetBSD uses the libc md4 routines which take bytes instead of bits */
@@ -518,7 +584,13 @@ NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
     MD4_CTX            md4Context;
 
     MD4Init(&md4Context);
-    MD4Update(&md4Context, (unsigned char *)secret, mdlen);
+    /* MD4Update can take at most 64 bytes at a time */
+    while (mdlen > 512) {
+       MD4Update(&md4Context, secret, 512);
+       secret += 64;
+       mdlen -= 512;
+    }
+    MD4Update(&md4Context, secret, mdlen);
     MD4Final(hash, &md4Context);
 
 }
@@ -532,7 +604,7 @@ ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
 
     /* Hash the Unicode version of the secret (== password). */
     ascii2unicode(secret, secret_len, unicodePassword);
-    NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
+    NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
 
     ChallengeResponse(rchallenge, PasswordHash, NTResponse);
 }
@@ -549,7 +621,7 @@ ChapMS2_NT(u_char *rchallenge, u_char PeerChallenge[16], char *username,
 
     /* Hash the Unicode version of the secret (== password). */
     ascii2unicode(secret, secret_len, unicodePassword);
-    NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
+    NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
 
     ChallengeResponse(Challenge, PasswordHash, NTResponse);
 }
@@ -637,8 +709,8 @@ GenerateAuthenticatorResponsePlain
 
     /* Hash (x2) the Unicode version of the secret (== password). */
     ascii2unicode(secret, secret_len, unicodePassword);
-    NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
-    NTPasswordHash((char *)PasswordHash, sizeof(PasswordHash),
+    NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
+    NTPasswordHash(PasswordHash, sizeof(PasswordHash),
                   PasswordHashHash);
 
     GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge,
@@ -813,7 +885,8 @@ ChapMS(u_char *rchallenge, char *secret, int secret_len,
     ChapMS_NT(rchallenge, secret, secret_len, &response[MS_CHAP_NTRESP]);
 
 #ifdef MSLANMAN
-    ChapMS_LANMan(rchallenge, secret, secret_len, &response);
+    ChapMS_LANMan(rchallenge, secret, secret_len,
+                 &response[MS_CHAP_LANMANRESP]);
 
     /* preferred method is set by option  */
     response[MS_CHAP_USENT] = !ms_lanman;
@@ -846,7 +919,7 @@ ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
     u_char *p = &response[MS_CHAP2_PEER_CHALLENGE];
     int i;
 
-    BZERO(response, sizeof(*response));
+    BZERO(response, MS_CHAP2_RESPONSE_LEN);
 
     /* Generate the Peer-Challenge if requested, or copy it if supplied. */
     if (!PeerChallenge)