*
*/
-#define RCSID "$Id: chap_ms.c,v 1.33 2004/11/12 09:57:43 paulus Exp $"
+#define RCSID "$Id: chap_ms.c,v 1.38 2007/12/01 20:10:51 carlsonj Exp $"
-#ifdef CHAPMS
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
+#if defined(SOL2)
+#include <net/ppp-comp.h>
+#else
+#include <linux/ppp-comp.h>
+#endif
-#include "pppd.h"
-#include "chap-new.h"
+#include "pppd-private.h"
+#include "options.h"
+#include "chap.h"
#include "chap_ms.h"
-#include "md4.h"
-#include "sha1.h"
-#include "pppcrypt.h"
#include "magic.h"
+#include "mppe.h"
+#include "crypto.h"
+#include "crypto_ms.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((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]));
-#ifdef MSLANMAN
-static void ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *));
+#ifdef UNIT_TEST
+#undef PPP_WITH_MPPE
#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 ascii2unicode (char[], int, u_char[]);
+static void NTPasswordHash (u_char *, int, unsigned char *);
+static int ChallengeResponse (u_char *, u_char *, u_char*);
+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
+ (char*, int, u_char[24], u_char[16], u_char *,
+ char *, u_char[41]);
+#ifdef PPP_WITH_MSLANMAN
+static void ChapMS_LANMan (u_char *, char *, int, u_char *);
#endif
-#ifdef MSLANMAN
+#ifdef PPP_WITH_MSLANMAN
bool ms_lanman = 0; /* Use LanMan password instead of NT */
/* Has meaning only with MS-CHAP challenges */
#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 PPP_WITH_MPPE
#ifdef DEBUGMPPEKEY
/* For MPPE debug */
/* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */
#include "fsm.h" /* Need to poke MPPE options */
#include "ccp.h"
-#include <net/ppp-comp.h>
#endif
/*
* Command-line options.
*/
-static option_t chapms_option_list[] = {
-#ifdef MSLANMAN
+static struct option chapms_option_list[] = {
+#ifdef PPP_WITH_MSLANMAN
{ "ms-lanman", o_bool, &ms_lanman,
"Use LanMan passwd when using MS-CHAP", 1 },
#endif
unsigned char *challenge, unsigned char *response,
char *message, int message_space)
{
- MS_ChapResponse *rmd;
- MS_ChapResponse md;
+ unsigned char md[MS_CHAP_RESPONSE_LEN];
int diff;
int challenge_len, response_len;
if (response_len != MS_CHAP_RESPONSE_LEN)
goto bad;
- rmd = (MS_ChapResponse *) response;
-
-#ifndef MSLANMAN
- if (!rmd->UseNT[0]) {
+#ifndef PPP_WITH_MSLANMAN
+ if (!response[MS_CHAP_USENT]) {
/* Should really propagate this into the error packet. */
notice("Peer request for LANMAN auth not supported");
goto bad;
#endif
/* Generate the expected response. */
- ChapMS(challenge, (char *)secret, secret_len, &md);
+ ChapMS(challenge, (char *)secret, secret_len, md);
-#ifdef MSLANMAN
+#ifdef PPP_WITH_MSLANMAN
/* Determine which part of response to verify against */
- if (!rmd->UseNT[0])
- diff = memcmp(&rmd->LANManResp, &md.LANManResp,
- sizeof(md.LANManResp));
+ if (!response[MS_CHAP_USENT])
+ diff = memcmp(&response[MS_CHAP_LANMANRESP],
+ &md[MS_CHAP_LANMANRESP], MS_CHAP_LANMANRESP_LEN);
else
#endif
- diff = memcmp(&rmd->NTResp, &md.NTResp, sizeof(md.NTResp));
+ diff = memcmp(&response[MS_CHAP_NTRESP], &md[MS_CHAP_NTRESP],
+ MS_CHAP_NTRESP_LEN);
if (diff == 0) {
slprintf(message, message_space, "Access granted");
unsigned char *challenge, unsigned char *response,
char *message, int message_space)
{
- MS_Chap2Response *rmd;
- MS_Chap2Response md;
+ unsigned char md[MS_CHAP2_RESPONSE_LEN];
char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
int challenge_len, response_len;
if (response_len != MS_CHAP2_RESPONSE_LEN)
goto bad; /* not even the right length */
- rmd = (MS_Chap2Response *) response;
-
/* Generate the expected response and our mutual auth. */
- ChapMS2(challenge, rmd->PeerChallenge, name,
- (char *)secret, secret_len, &md,
+ ChapMS2(challenge, &response[MS_CHAP2_PEER_CHALLENGE], name,
+ (char *)secret, secret_len, md,
(unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR);
/* compare MDs and send the appropriate status */
* Special thanks to Alex Swiridov <say@real.kharkov.ua> for
* help debugging this.
*/
- if (memcmp(md.NTResp, rmd->NTResp, sizeof(md.NTResp)) == 0) {
- if (rmd->Flags[0])
+ if (memcmp(&md[MS_CHAP2_NTRESP], &response[MS_CHAP2_NTRESP],
+ MS_CHAP2_NTRESP_LEN) == 0) {
+ if (response[MS_CHAP2_FLAGS])
slprintf(message, message_space, "S=%s", saresponse);
else
slprintf(message, message_space, "S=%s M=%s",
{
challenge++; /* skip length, should be 8 */
*response++ = MS_CHAP_RESPONSE_LEN;
- ChapMS(challenge, secret, secret_len, (MS_ChapResponse *) response);
+ 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
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,
- (MS_Chap2Response *) 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) {
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;
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.");
* 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. */
free(msg);
}
-static void
+static int
ChallengeResponse(u_char *challenge,
- u_char PasswordHash[MD4_SIGNATURE_SIZE],
- u_char response[24])
+ u_char *PasswordHash,
+ u_char *response)
{
- u_char ZPasswordHash[21];
+ u_char ZPasswordHash[24];
+ PPP_CIPHER_CTX *ctx;
BZERO(ZPasswordHash, sizeof(ZPasswordHash));
- BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
+ BCOPY(PasswordHash, ZPasswordHash, MD4_DIGEST_LENGTH);
#if 0
dbglog("ChallengeResponse - ZPasswordHash %.*B",
sizeof(ZPasswordHash), ZPasswordHash);
#endif
- (void) DesSetkey(ZPasswordHash + 0);
- DesEncrypt(challenge, response + 0);
- (void) DesSetkey(ZPasswordHash + 7);
- DesEncrypt(challenge, response + 8);
- (void) DesSetkey(ZPasswordHash + 14);
- DesEncrypt(challenge, response + 16);
+ if (DesEncrypt(challenge, ZPasswordHash + 0, response + 0) &&
+ DesEncrypt(challenge, ZPasswordHash + 7, response + 8) &&
+ DesEncrypt(challenge, ZPasswordHash + 14, response + 16))
+ return 1;
#if 0
dbglog("ChallengeResponse - response %.24B", response);
#endif
+ return 0;
}
void
char *username, u_char Challenge[8])
{
- SHA1_CTX sha1Context;
- u_char sha1Hash[SHA1_SIGNATURE_SIZE];
- char *user;
+ PPP_MD_CTX* ctx;
+ u_char hash[SHA_DIGEST_LENGTH];
+ int hash_len;
+ const char *user;
/* remove domain from "domain\username" */
if ((user = strrchr(username, '\\')) != NULL)
++user;
else
user = username;
+
+ ctx = PPP_MD_CTX_new();
+ if (ctx != NULL) {
+
+ if (PPP_DigestInit(ctx, PPP_sha1())) {
- SHA1_Init(&sha1Context);
- SHA1_Update(&sha1Context, PeerChallenge, 16);
- SHA1_Update(&sha1Context, rchallenge, 16);
- SHA1_Update(&sha1Context, (unsigned char *)user, strlen(user));
- SHA1_Final(sha1Hash, &sha1Context);
+ if (PPP_DigestUpdate(ctx, PeerChallenge, 16)) {
- BCOPY(sha1Hash, Challenge, 8);
+ if (PPP_DigestUpdate(ctx, rchallenge, 16)) {
+
+ if (PPP_DigestUpdate(ctx, user, strlen(user))) {
+
+ hash_len = SHA_DIGEST_LENGTH;
+ if (PPP_DigestFinal(ctx, hash, &hash_len)) {
+
+ BCOPY(hash, Challenge, 8);
+ }
+ }
+ }
+ }
+ }
+
+ PPP_MD_CTX_free(ctx);
+ }
}
/*
}
static void
-NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
+NTPasswordHash(u_char *secret, int secret_len, unsigned char* hash)
{
-#ifdef __NetBSD__
- /* NetBSD uses the libc md4 routines which take bytes instead of bits */
- int mdlen = secret_len;
-#else
- int mdlen = secret_len * 8;
-#endif
- MD4_CTX md4Context;
+ PPP_MD_CTX* ctx = PPP_MD_CTX_new();
+ if (ctx != NULL) {
- MD4Init(&md4Context);
- MD4Update(&md4Context, (unsigned char *)secret, mdlen);
- MD4Final(hash, &md4Context);
+ if (PPP_DigestInit(ctx, PPP_md4())) {
+ if (PPP_DigestUpdate(ctx, secret, secret_len)) {
+
+ int hash_len = MD4_DIGEST_LENGTH;
+ PPP_DigestFinal(ctx, hash, &hash_len);
+ }
+ }
+
+ PPP_MD_CTX_free(ctx);
+ }
}
static void
u_char NTResponse[24])
{
u_char unicodePassword[MAX_NT_PASSWORD * 2];
- u_char PasswordHash[MD4_SIGNATURE_SIZE];
+ u_char PasswordHash[MD4_DIGEST_LENGTH];
/* 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);
}
static void
-ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
+ChapMS2_NT(u_char *rchallenge, u_char PeerChallenge[16], char *username,
char *secret, int secret_len, u_char NTResponse[24])
{
u_char unicodePassword[MAX_NT_PASSWORD * 2];
- u_char PasswordHash[MD4_SIGNATURE_SIZE];
+ u_char PasswordHash[MD4_DIGEST_LENGTH];
u_char Challenge[8];
- ChallengeHash(PeerChallenge, (unsigned char *)rchallenge, username,
- Challenge);
+ ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
/* 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);
}
-#ifdef MSLANMAN
+#ifdef PPP_WITH_MSLANMAN
static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
static void
ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
- MS_ChapResponse *response)
+ unsigned char *response)
{
int i;
u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
- u_char PasswordHash[MD4_SIGNATURE_SIZE];
+ u_char PasswordHash[MD4_DIGEST_LENGTH];
/* LANMan password is case insensitive */
BZERO(UcasePassword, sizeof(UcasePassword));
DesEncrypt( StdText, PasswordHash + 0 );
(void) DesSetkey(UcasePassword + 7);
DesEncrypt( StdText, PasswordHash + 8 );
- ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
+ ChallengeResponse(rchallenge, PasswordHash, &response[MS_CHAP_LANMANRESP]);
}
#endif
void
-GenerateAuthenticatorResponse(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
- u_char NTResponse[24], u_char PeerChallenge[16],
- u_char *rchallenge, char *username,
- u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
+GenerateAuthenticatorResponse(unsigned char* PasswordHashHash,
+ unsigned char *NTResponse, unsigned char *PeerChallenge,
+ unsigned char *rchallenge, char *username,
+ unsigned char *authResponse)
{
/*
* "Magic" constants used in response generation, from RFC 2759.
0x6E };
int i;
- SHA1_CTX sha1Context;
- u_char Digest[SHA1_SIGNATURE_SIZE];
+ PPP_MD_CTX *ctx;
+ u_char Digest[SHA_DIGEST_LENGTH] = {};
+ int hash_len;
u_char Challenge[8];
- SHA1_Init(&sha1Context);
- SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
- SHA1_Update(&sha1Context, NTResponse, 24);
- SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
- SHA1_Final(Digest, &sha1Context);
+ ctx = PPP_MD_CTX_new();
+ if (ctx != NULL) {
+
+ if (PPP_DigestInit(ctx, PPP_sha1())) {
+ if (PPP_DigestUpdate(ctx, PasswordHashHash, MD4_DIGEST_LENGTH)) {
+
+ if (PPP_DigestUpdate(ctx, NTResponse, 24)) {
+
+ if (PPP_DigestUpdate(ctx, Magic1, sizeof(Magic1))) {
+
+ hash_len = sizeof(Digest);
+ PPP_DigestFinal(ctx, Digest, &hash_len);
+ }
+ }
+ }
+ }
+ PPP_MD_CTX_free(ctx);
+ }
+
ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
- SHA1_Init(&sha1Context);
- SHA1_Update(&sha1Context, Digest, sizeof(Digest));
- SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
- SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
- SHA1_Final(Digest, &sha1Context);
+ ctx = PPP_MD_CTX_new();
+ if (ctx != NULL) {
+
+ if (PPP_DigestInit(ctx, PPP_sha1())) {
+
+ if (PPP_DigestUpdate(ctx, Digest, sizeof(Digest))) {
+
+ if (PPP_DigestUpdate(ctx, Challenge, sizeof(Challenge))) {
+
+ if (PPP_DigestUpdate(ctx, Magic2, sizeof(Magic2))) {
+
+ hash_len = sizeof(Digest);
+ PPP_DigestFinal(ctx, Digest, &hash_len);
+ }
+ }
+ }
+ }
+
+ PPP_MD_CTX_free(ctx);
+ }
/* Convert to ASCII hex string. */
- for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
- sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]);
+ for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++) {
+ sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]);
+ }
}
u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
{
u_char unicodePassword[MAX_NT_PASSWORD * 2];
- u_char PasswordHash[MD4_SIGNATURE_SIZE];
- u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
+ u_char PasswordHash[MD4_DIGEST_LENGTH];
+ u_char PasswordHashHash[MD4_DIGEST_LENGTH];
/* 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,
}
-#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;
-}
+#ifdef PPP_WITH_MPPE
/*
* Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
{
u_char unicodePassword[MAX_NT_PASSWORD * 2];
- u_char PasswordHash[MD4_SIGNATURE_SIZE];
- u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
+ u_char PasswordHash[MD4_DIGEST_LENGTH];
+ u_char PasswordHashHash[MD4_DIGEST_LENGTH];
/* Hash (x2) the Unicode version of the secret (== password). */
ascii2unicode(secret, secret_len, unicodePassword);
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);
}
/*
SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
{
u_char unicodePassword[MAX_NT_PASSWORD * 2];
- u_char PasswordHash[MD4_SIGNATURE_SIZE];
- u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
+ u_char PasswordHash[MD4_DIGEST_LENGTH];
+ u_char PasswordHashHash[MD4_DIGEST_LENGTH];
/* Hash (x2) the Unicode version of the secret (== password). */
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 */
+#endif /* PPP_WITH_MPPE */
void
ChapMS(u_char *rchallenge, char *secret, int secret_len,
- MS_ChapResponse *response)
+ unsigned char *response)
{
- BZERO(response, sizeof(*response));
+ BZERO(response, MS_CHAP_RESPONSE_LEN);
- ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
+ ChapMS_NT(rchallenge, secret, secret_len, &response[MS_CHAP_NTRESP]);
-#ifdef MSLANMAN
- ChapMS_LANMan(rchallenge, secret, secret_len, response);
+#ifdef PPP_WITH_MSLANMAN
+ ChapMS_LANMan(rchallenge, secret, secret_len,
+ &response[MS_CHAP_LANMANRESP]);
/* preferred method is set by option */
- response->UseNT[0] = !ms_lanman;
+ response[MS_CHAP_USENT] = !ms_lanman;
#else
- response->UseNT[0] = 1;
+ response[MS_CHAP_USENT] = 1;
#endif
-#ifdef MPPE
+#ifdef PPP_WITH_MPPE
Set_Start_Key(rchallenge, secret, secret_len);
#endif
}
/*
- * If PeerChallenge is NULL, one is generated and response->PeerChallenge
- * is filled in. Call this way when generating a response.
- * If PeerChallenge is supplied, it is copied into response->PeerChallenge.
+ * If PeerChallenge is NULL, one is generated and the PeerChallenge
+ * field of response is filled in. Call this way when generating a response.
+ * If PeerChallenge is supplied, it is copied into the PeerChallenge field.
* Call this way when verifying a response (or debugging).
- * Do not call with PeerChallenge = response->PeerChallenge.
+ * Do not call with PeerChallenge = response.
*
- * response->PeerChallenge is then used for calculation of the
+ * The PeerChallenge field of response is then used for calculation of the
* Authenticator Response.
*/
void
-ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
- char *user, char *secret, int secret_len, MS_Chap2Response *response,
+ChapMS2(unsigned char *rchallenge, unsigned char *PeerChallenge,
+ char *user, char *secret, int secret_len, unsigned char *response,
u_char authResponse[], int authenticator)
{
/* ARGSUSED */
- u_char *p = response->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)
- for (i = 0; i < sizeof(response->PeerChallenge); i++)
+ for (i = 0; i < MS_CHAP2_PEER_CHAL_LEN; i++)
*p++ = (u_char) (drand48() * 0xff);
else
- BCOPY(PeerChallenge, response->PeerChallenge,
- sizeof(response->PeerChallenge));
+ BCOPY(PeerChallenge, &response[MS_CHAP2_PEER_CHALLENGE],
+ MS_CHAP2_PEER_CHAL_LEN);
/* Generate the NT-Response */
- ChapMS2_NT((char *)rchallenge, response->PeerChallenge, user,
- secret, secret_len, response->NTResp);
+ ChapMS2_NT(rchallenge, &response[MS_CHAP2_PEER_CHALLENGE], user,
+ secret, secret_len, &response[MS_CHAP2_NTRESP]);
/* Generate the Authenticator Response. */
- GenerateAuthenticatorResponsePlain(secret, secret_len, response->NTResp,
- response->PeerChallenge, rchallenge,
- user, authResponse);
-
-#ifdef MPPE
- SetMasterKeys(secret, secret_len, response->NTResp, authenticator);
+ GenerateAuthenticatorResponsePlain(secret, secret_len,
+ &response[MS_CHAP2_NTRESP],
+ &response[MS_CHAP2_PEER_CHALLENGE],
+ rchallenge, user, authResponse);
+
+#ifdef PPP_WITH_MPPE
+ SetMasterKeys(secret, secret_len,
+ &response[MS_CHAP2_NTRESP], authenticator);
#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 */
chapms_handle_failure,
};
+#ifndef UNIT_TEST
void
chapms_init(void)
{
chap_register_digest(&chapms_digest);
chap_register_digest(&chapms2_digest);
- add_options(chapms_option_list);
+ ppp_add_options(chapms_option_list);
+}
+#else
+
+#include <time.h>
+
+int debug = 1;
+int error_count = 0;
+int unsuccess = 0;
+
+void random_bytes(unsigned char *bytes, int len)
+{
+ int i = 0;
+ srand(time(NULL));
+ while (i < len) {
+ bytes[i++] = (unsigned char) rand();
+ }
+}
+
+
+int test_chap_v1(void) {
+ char *secret = "MyPw";
+
+ unsigned char challenge[8] = {
+ 0x10, 0x2D, 0xB5, 0xDF, 0x08, 0x5D, 0x30, 0x41
+ };
+ unsigned char response[MS_CHAP_RESPONSE_LEN] = {
+ };
+ unsigned char result[MS_CHAP_RESPONSE_LEN] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ 0x4E, 0x9D, 0x3C, 0x8F, 0x9C, 0xFD, 0x38, 0x5D,
+ 0x5B, 0xF4, 0xD3, 0x24, 0x67, 0x91, 0x95, 0x6C,
+ 0xA4, 0xC3, 0x51, 0xAB, 0x40, 0x9A, 0x3D, 0x61,
+
+ 0x01
+ };
+
+ ChapMS(challenge, secret, strlen(secret), response);
+ return memcmp(response, result, MS_CHAP_RESPONSE_LEN);
+}
+
+int test_chap_v2(void) {
+ char *secret = "clientPass";
+ char *name = "User";
+
+ char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
+ char *saresult = "407A5589115FD0D6209F510FE9C04566932CDA56";
+
+ unsigned char authenticator[16] = {
+ 0x5B, 0x5D, 0x7C, 0x7D, 0x7B, 0x3F, 0x2F, 0x3E,
+ 0x3C, 0x2C, 0x60, 0x21, 0x32, 0x26, 0x26, 0x28
+ };
+ unsigned char peerchallenge[16] = {
+ 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A,
+ 0x28, 0x29, 0x5F, 0x2B, 0x3A, 0x33, 0x7C, 0x7E
+ };
+ unsigned char result[MS_CHAP_NTRESP_LEN] = {
+ 0x82, 0x30, 0x9E, 0xCD, 0x8D, 0x70, 0x8B, 0x5E,
+ 0xA0, 0x8F, 0xAA, 0x39, 0x81, 0xCD, 0x83, 0x54,
+ 0x42, 0x33, 0x11, 0x4A, 0x3D, 0x85, 0xD6, 0xDF
+ };
+
+ unsigned char response[MS_CHAP2_RESPONSE_LEN] = {
+ };
+
+ ChapMS2(authenticator, peerchallenge, name,
+ secret, strlen(secret), response,
+ (unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR);
+
+ return memcmp(&response[MS_CHAP2_NTRESP], result, MS_CHAP2_NTRESP_LEN) ||
+ strncmp(saresponse, saresult, MS_AUTH_RESPONSE_LENGTH);
}
-#endif /* CHAPMS */
+int main(int argc, char *argv[]) {
+
+ PPP_crypto_init();
+
+ if (test_chap_v1()) {
+ printf("CHAPv1 failed\n");
+ return -1;
+ }
+
+ if (test_chap_v2()) {
+ printf("CHAPv2 failed\n");
+ return -1;
+ }
+
+ PPP_crypto_deinit();
+
+ printf("Success\n");
+ return 0;
+}
+
+#endif /* UNIT_TEST */
+