From e79f90482eb6f90c3f1fe7732258756d2ea0277f Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 28 May 1996 00:42:31 +0000 Subject: [PATCH] mods for optional MS-CHAP support --- pppd/chap.c | 39 +++++++++-- pppd/chap.h | 21 +++++- pppd/chap_ms.c | 184 +++++++++++++++++++++++++++++++++++++++++++++++++ pppd/chap_ms.h | 32 +++++++++ pppd/lcp.c | 8 ++- 5 files changed, 276 insertions(+), 8 deletions(-) create mode 100644 pppd/chap_ms.c create mode 100644 pppd/chap_ms.h diff --git a/pppd/chap.c b/pppd/chap.c index 99b1175..1dad8f6 100644 --- a/pppd/chap.c +++ b/pppd/chap.c @@ -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; diff --git a/pppd/chap.h b/pppd/chap.h index 36bad2b..036aef1 100644 --- a/pppd/chap.h +++ b/pppd/chap.h @@ -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 index 0000000..c69f4b6 --- /dev/null +++ b/pppd/chap_ms.c @@ -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 +#include +#include +#include + +#include "pppd.h" +#include "chap.h" +#include "chap_ms.h" +#include "md4.h" + + +#ifdef CHAPMS +#include + +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 index 0000000..2d7c7e9 --- /dev/null +++ b/pppd/chap_ms.h @@ -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__ */ diff --git a/pppd/lcp.c b/pppd/lcp.c index 40ca0f6..7d0a406 100644 --- a/pppd/lcp.c +++ b/pppd/lcp.c @@ -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); -- 2.39.2