]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/chap_ms.c
pppd: Expose the MPPE keys generated through an API (#267)
[ppp.git] / pppd / chap_ms.c
index 75724c514b0946ad24e7c06d52bcf3eff9eca996..d315ab4acd0182258fb25bee21f472e2d021f42b 100644 (file)
@@ -74,7 +74,7 @@
  *
  */
 
-#define RCSID  "$Id: chap_ms.c,v 1.36 2006/05/21 11:56:40 paulus Exp $"
+#define RCSID  "$Id: chap_ms.c,v 1.38 2007/12/01 20:10:51 carlsonj Exp $"
 
 #ifdef CHAPMS
 
 #include "sha1.h"
 #include "pppcrypt.h"
 #include "magic.h"
-
-static const char rcsid[] = RCSID;
-
-
-static void    ascii2unicode __P((char[], int, u_char[]));
-static void    NTPasswordHash __P((u_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]));
+#include "mppe.h"
+
+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 *));
-#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    ChapMS_LANMan (u_char *, char *, int, u_char *);
 #endif
 
 #ifdef MSLANMAN
@@ -121,10 +114,6 @@ bool       ms_lanman = 0;          /* Use LanMan password instead of NT */
 #endif
 
 #ifdef MPPE
-u_char mppe_send_key[MPPE_MAX_KEY_LEN];
-u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
-int mppe_keys_set = 0;         /* Have the MPPE keys been set? */
-
 #ifdef DEBUGMPPEKEY
 /* For MPPE debug */
 /* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */
@@ -320,25 +309,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 +403,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 +413,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.");
@@ -653,28 +709,6 @@ GenerateAuthenticatorResponsePlain
 
 
 #ifdef MPPE
-/*
- * Set mppe_xxxx_key from the NTPasswordHashHash.
- * RFC 2548 (RADIUS support) requires us to export this function (ugh).
- */
-void
-mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
-{
-    SHA1_CTX   sha1Context;
-    u_char     Digest[SHA1_SIGNATURE_SIZE];    /* >= MPPE_MAX_KEY_LEN */
-
-    SHA1_Init(&sha1Context);
-    SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
-    SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
-    SHA1_Update(&sha1Context, rchallenge, 8);
-    SHA1_Final(Digest, &sha1Context);
-
-    /* Same key in both directions. */
-    BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
-    BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
-
-    mppe_keys_set = 1;
-}
 
 /*
  * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
@@ -691,104 +725,7 @@ Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
 
-    mppe_set_keys(rchallenge, PasswordHashHash);
-}
-
-/*
- * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
- *
- * This helper function used in the Winbind module, which gets the
- * NTHashHash from the server.
- */
-void
-mppe_set_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
-              u_char NTResponse[24], int IsServer)
-{
-    SHA1_CTX   sha1Context;
-    u_char     MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
-    u_char     Digest[SHA1_SIGNATURE_SIZE];    /* >= MPPE_MAX_KEY_LEN */
-
-    u_char SHApad1[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 };
-    u_char SHApad2[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 };
-
-    /* "This is the MPPE Master Key" */
-    u_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 };
-    /* "On the client side, this is the send key; "
-       "on the server side, it is the receive key." */
-    u_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 };
-    /* "On the client side, this is the receive key; "
-       "on the server side, it is the send key." */
-    u_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 };
-    u_char *s;
-
-    SHA1_Init(&sha1Context);
-    SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
-    SHA1_Update(&sha1Context, NTResponse, 24);
-    SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
-    SHA1_Final(MasterKey, &sha1Context);
-
-    /*
-     * generate send key
-     */
-    if (IsServer)
-       s = Magic3;
-    else
-       s = Magic2;
-    SHA1_Init(&sha1Context);
-    SHA1_Update(&sha1Context, MasterKey, 16);
-    SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
-    SHA1_Update(&sha1Context, s, 84);
-    SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
-    SHA1_Final(Digest, &sha1Context);
-
-    BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
-
-    /*
-     * generate recv key
-     */
-    if (IsServer)
-       s = Magic2;
-    else
-       s = Magic3;
-    SHA1_Init(&sha1Context);
-    SHA1_Update(&sha1Context, MasterKey, 16);
-    SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
-    SHA1_Update(&sha1Context, s, 84);
-    SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
-    SHA1_Final(Digest, &sha1Context);
-
-    BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
-
-    mppe_keys_set = 1;
+    mppe_set_chapv1(rchallenge, PasswordHashHash);
 }
 
 /*
@@ -804,7 +741,7 @@ SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
     ascii2unicode(secret, secret_len, unicodePassword);
     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
-    mppe_set_keys2(PasswordHashHash, NTResponse, IsServer);
+    mppe_set_chapv2(PasswordHashHash, NTResponse, IsServer);
 }
 
 #endif /* MPPE */
@@ -819,7 +756,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;
@@ -852,7 +790,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)
@@ -878,38 +816,6 @@ ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
 #endif
 }
 
-#ifdef MPPE
-/*
- * Set MPPE options from plugins.
- */
-void
-set_mppe_enc_types(int policy, int types)
-{
-    /* Early exit for unknown policies. */
-    if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
-       policy != MPPE_ENC_POL_ENC_REQUIRED)
-       return;
-
-    /* Don't modify MPPE if it's optional and wasn't already configured. */
-    if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
-       return;
-
-    /*
-     * Disable undesirable encryption types.  Note that we don't ENABLE
-     * any encryption types, to avoid overriding manual configuration.
-     */
-    switch(types) {
-       case MPPE_ENC_TYPES_RC4_40:
-           ccp_wantoptions[0].mppe &= ~MPPE_OPT_128;   /* disable 128-bit */
-           break;
-       case MPPE_ENC_TYPES_RC4_128:
-           ccp_wantoptions[0].mppe &= ~MPPE_OPT_40;    /* disable 40-bit */
-           break;
-       default:
-           break;
-    }
-}
-#endif /* MPPE */
 
 static struct chap_digest_type chapms_digest = {
        CHAP_MICROSOFT,         /* code */