mods for optional MS-CHAP support
authorPaul Mackerras <paulus@samba.org>
Tue, 28 May 1996 00:42:31 +0000 (00:42 +0000)
committerPaul Mackerras <paulus@samba.org>
Tue, 28 May 1996 00:42:31 +0000 (00:42 +0000)
pppd/chap.c
pppd/chap.h
pppd/chap_ms.c [new file with mode: 0644]
pppd/chap_ms.h [new file with mode: 0644]
pppd/lcp.c

index 99b11758bf5989b64a1afa6bb2d0e95e83530ec9..1dad8f649b3d4b91c491352cdf4231399aa52950 100644 (file)
@@ -1,5 +1,20 @@
 /*
- * chap.c - Crytographic Handshake Authentication Protocol.
+ * chap.c - Challenge Handshake Authentication Protocol.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University.  The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
  * Copyright (c) 1991 Gregory M. Christy.
  * All rights reserved.
@@ -19,7 +34,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: chap.c,v 1.11 1996/04/04 03:35:58 paulus Exp $";
+static char rcsid[] = "$Id: chap.c,v 1.12 1996/05/28 00:42:27 paulus Exp $";
 #endif
 
 /*
@@ -35,6 +50,9 @@ static char rcsid[] = "$Id: chap.c,v 1.11 1996/04/04 03:35:58 paulus Exp $";
 #include "pppd.h"
 #include "chap.h"
 #include "md5.h"
+#ifdef CHAPMS
+#include "chap_ms.h"
+#endif
 
 struct protent chap_protent = {
     PPP_CHAP, ChapInit, ChapInput, ChapProtocolReject,
@@ -376,9 +394,16 @@ ChapReceiveChallenge(cstate, inp, id, len)
     BCOPY(inp, rhostname, len);
     rhostname[len] = '\000';
 
-    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field: %s",
+    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field '%s'",
               rhostname));
 
+    /* Microsoft doesn't send their name back in the PPP packet */
+    if (rhostname[0] == 0 && cstate->resp_type == CHAP_MICROSOFT) {
+       strcpy(rhostname, remote_name);
+       CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: using '%s' as remote name",
+                  rhostname));
+    }
+
     /* get secret for authenticating ourselves with the specified host */
     if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
                    secret, &secret_len, 0)) {
@@ -397,7 +422,7 @@ ChapReceiveChallenge(cstate, inp, id, len)
     /*  generate MD based on negotiated type */
     switch (cstate->resp_type) { 
 
-    case CHAP_DIGEST_MD5:              /* only MD5 is defined for now */
+    case CHAP_DIGEST_MD5:
        MD5Init(&mdContext);
        MD5Update(&mdContext, &cstate->resp_id, 1);
        MD5Update(&mdContext, secret, secret_len);
@@ -407,6 +432,12 @@ ChapReceiveChallenge(cstate, inp, id, len)
        cstate->resp_length = MD5_SIGNATURE_SIZE;
        break;
 
+#ifdef CHAPMS
+    case CHAP_MICROSOFT:
+       ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
+       break;
+#endif
+
     default:
        CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->resp_type));
        return;
index 36bad2b6414ef8818bd1d00e1b0a2806530e666b..036aef10dfc4cac57cd90160c34c531157429202 100644 (file)
@@ -1,5 +1,20 @@
 /*
- * chap.h - Cryptographic Handshake Authentication Protocol definitions.
+ * chap.h - Challenge Handshake Authentication Protocol definitions.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University.  The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
  * Copyright (c) 1991 Gregory M. Christy
  * All rights reserved.
@@ -15,7 +30,7 @@
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- * $Id: chap.h,v 1.4 1995/12/18 03:46:21 paulus Exp $
+ * $Id: chap.h,v 1.5 1996/05/28 00:42:28 paulus Exp $
  */
 
 #ifndef __CHAP_INCLUDE__
@@ -29,6 +44,8 @@
 
 #define CHAP_DIGEST_MD5                5       /* use MD5 algorithm */
 #define MD5_SIGNATURE_SIZE     16      /* 16 bytes in a MD5 message digest */
+#define CHAP_MICROSOFT         0x80    /* use Microsoft-compatible alg. */
+#define MS_CHAP_RESPONSE_LEN   49      /* Response length for MS-CHAP */
 
 #define CHAP_CHALLENGE         1
 #define CHAP_RESPONSE          2
diff --git a/pppd/chap_ms.c b/pppd/chap_ms.c
new file mode 100644 (file)
index 0000000..c69f4b6
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * chap_ms.c - Microsoft MS-CHAP compatible implementation.
+ *
+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
+ * http://www.strataware.com/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Eric Rosenquist.  The name of the author may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: chap_ms.c,v 1.1 1996/05/28 00:42:30 paulus Exp $";
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <syslog.h>
+
+#include "pppd.h"
+#include "chap.h"
+#include "chap_ms.h"
+#include "md4.h"
+
+
+#ifdef CHAPMS
+#include <des.h>
+
+typedef struct {
+    u_char LANManResp[24];
+    u_char NTResp[24];
+    u_char UseNT;              /* If 1, ignore the LANMan response field */
+} MS_ChapResponse;
+/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
+   in case this struct gets padded. */
+
+
+static void    DesEncrypt __P((u_char *, u_char *, u_char *));
+static void    MakeKey __P((u_char *, u_char *));
+
+
+static void
+ChallengeResponse(challenge, pwHash, response)
+    u_char *challenge; /* IN   8 octets */
+    u_char *pwHash;    /* IN  16 octets */
+    u_char *response;  /* OUT 24 octets */
+{
+    char    ZPasswordHash[21];
+
+    BZERO(ZPasswordHash, sizeof(ZPasswordHash));
+    BCOPY(pwHash, ZPasswordHash, 16);
+
+#if 0
+    log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash");
+#endif
+
+    DesEncrypt(challenge, ZPasswordHash +  0, response + 0);
+    DesEncrypt(challenge, ZPasswordHash +  7, response + 8);
+    DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
+
+#if 0
+    log_packet(response, 24, "ChallengeResponse - response");
+#endif
+}
+
+
+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 : %02X%02X%02X%02X%02X%02X%02X%02X",
+              clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
+#endif
+
+    des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
+
+#if 0
+    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X",
+              cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
+#endif
+}
+
+
+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;
+}
+
+
+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);
+
+    des_set_odd_parity((des_cblock *)des_key);
+
+#if 0
+    CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X",
+              key[0], key[1], key[2], key[3], key[4], key[5], key[6]));
+    CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X",
+              des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7]));
+#endif
+}
+
+#endif /* CHAPMS */
+
+
+void
+ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len)
+    chap_state *cstate;
+    char *rchallenge;
+    int rchallenge_len;
+    char *secret;
+    int secret_len;
+{
+#ifdef CHAPMS
+    int                        i;
+    MDstruct           md4Context;
+    MS_ChapResponse    response;
+    u_char             unicodePassword[MAX_NT_PASSWORD * 2];
+
+#if 0
+    CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
+#endif
+
+    BZERO(&response, sizeof(response));
+
+    /* 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];
+
+    MDbegin(&md4Context);
+    MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8);        /* Unicode is 2 bytes/char, *8 for bit count */
+    MDupdate(&md4Context, NULL, 0);    /* Tell MD4 we're done */
+
+    ChallengeResponse(rchallenge, (char *)md4Context.buffer, response.NTResp);
+
+    response.UseNT = 1;
+
+    BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
+    cstate->resp_length = MS_CHAP_RESPONSE_LEN;
+#endif /* CHAPMS */
+}
diff --git a/pppd/chap_ms.h b/pppd/chap_ms.h
new file mode 100644 (file)
index 0000000..2d7c7e9
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * chap.h - Challenge Handshake Authentication Protocol definitions.
+ *
+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
+ * http://www.strataware.com/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Eric Rosenquist.  The name of the author may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: chap_ms.h,v 1.1 1996/05/28 00:42:31 paulus Exp $
+ */
+
+#ifndef __CHAPMS_INCLUDE__
+
+#define MAX_NT_PASSWORD        256     /* Maximum number of (Unicode) chars in an NT password */
+
+void ChapMS __P((chap_state *, char *, int, char *, int));
+
+#define __CHAPMS_INCLUDE__
+#endif /* __CHAPMS_INCLUDE__ */
index 40ca0f6b8cb5318aa9e58037fff657efca0ce1f3..7d0a40677776f1b841e568aaa85a2ce66c364e5e 100644 (file)
@@ -18,7 +18,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: lcp.c,v 1.25 1996/04/04 03:58:24 paulus Exp $";
+static char rcsid[] = "$Id: lcp.c,v 1.26 1996/05/28 00:41:13 paulus Exp $";
 #endif
 
 /*
@@ -1204,7 +1204,11 @@ lcp_reqci(f, inp, lenp, reject_if_disagree)
                    break;
                }
                GETCHAR(cichar, p);     /* get digest type*/
-               if (cichar != ao->chap_mdtype) {
+               if (cichar != CHAP_DIGEST_MD5
+#ifdef CHAPMS
+                   && cichar != CHAP_MICROSOFT
+#endif
+                   ) {
                    orc = CONFNAK;
                    PUTCHAR(CI_AUTHTYPE, nakp);
                    PUTCHAR(CILEN_CHAP, nakp);