ppp/pppd/chap-md5.c
Paul Mackerras 05b737b37f pppd: Make sure we don't return an initialized CHAP Response length
If anything goes wrong in preparing a CHAP Response, return a 0-length
response instead of leaving the length field uninitialized.  Also
print a warning message to say that something went wrong.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
2024-08-20 17:31:45 +10:00

155 lines
3.9 KiB
C

/*
* chap-md5.c - New CHAP/MD5 implementation.
*
* Copyright (c) 2003 Paul Mackerras. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. The name(s) of the authors of this software must not be used to
* endorse or promote products derived from this software without
* prior written permission.
*
* 3. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Paul Mackerras
* <paulus@ozlabs.org>".
*
* THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define RCSID "$Id: chap-md5.c,v 1.4 2004/11/09 22:39:25 paulus Exp $"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include "pppd-private.h"
#include "chap.h"
#include "chap-md5.h"
#include "magic.h"
#include "crypto.h"
#define MD5_MIN_CHALLENGE 16
#define MD5_MAX_CHALLENGE 24
static void
chap_md5_generate_challenge(unsigned char *cp)
{
int clen;
clen = (int)(drand48() * (MD5_MAX_CHALLENGE - MD5_MIN_CHALLENGE))
+ MD5_MIN_CHALLENGE;
*cp++ = clen;
random_bytes(cp, clen);
}
static int
chap_md5_verify_response(int id, char *name,
unsigned char *secret, int secret_len,
unsigned char *challenge, unsigned char *response,
char *message, int message_space)
{
unsigned char idbyte = id;
unsigned char hash[MD5_DIGEST_LENGTH];
unsigned int hash_len = MD5_DIGEST_LENGTH;
int challenge_len, response_len;
bool success = 0;
challenge_len = *challenge++;
response_len = *response++;
if (response_len == MD5_DIGEST_LENGTH) {
/* Generate hash of ID, secret, challenge */
PPP_MD_CTX* ctx = PPP_MD_CTX_new();
if (ctx) {
if (PPP_DigestInit(ctx, PPP_md5())) {
if (PPP_DigestUpdate(ctx, &idbyte, 1)) {
if (PPP_DigestUpdate(ctx, secret, secret_len)) {
if (PPP_DigestUpdate(ctx, challenge, challenge_len)) {
if (PPP_DigestFinal(ctx, hash, &hash_len)) {
success = 1;
}
}
}
}
}
PPP_MD_CTX_free(ctx);
}
}
if (success && memcmp(hash, response, hash_len) == 0) {
slprintf(message, message_space, "Access granted");
return 1;
}
slprintf(message, message_space, "Access denied");
return 0;
}
static void
chap_md5_make_response(unsigned char *response, int id, char *our_name,
unsigned char *challenge, char *secret, int secret_len,
unsigned char *private)
{
unsigned char idbyte = id;
int challenge_len = *challenge++;
int hash_len = MD5_DIGEST_LENGTH;
response[0] = 0;
PPP_MD_CTX* ctx = PPP_MD_CTX_new();
if (ctx) {
if (PPP_DigestInit(ctx, PPP_md5())) {
if (PPP_DigestUpdate(ctx, &idbyte, 1)) {
if (PPP_DigestUpdate(ctx, secret, secret_len)) {
if (PPP_DigestUpdate(ctx, challenge, challenge_len)) {
if (PPP_DigestFinal(ctx, &response[1], &hash_len)) {
response[0] = hash_len;
}
}
}
}
}
PPP_MD_CTX_free(ctx);
}
if (response[0] == 0)
warn("Error occurred in preparing CHAP-Response");
}
static struct chap_digest_type md5_digest = {
CHAP_MD5, /* code */
chap_md5_generate_challenge,
chap_md5_verify_response,
chap_md5_make_response,
NULL, /* check_success */
NULL, /* handle_failure */
};
void
chap_md5_init(void)
{
chap_register_digest(&md5_digest);
}