2 * chap-md5.c - New CHAP/MD5 implementation.
4 * Copyright (c) 2003-2024 Paul Mackerras. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
18 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
19 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
20 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
21 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
23 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
24 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
33 #include "pppd-private.h"
39 #define MD5_MIN_CHALLENGE 16
40 #define MD5_MAX_CHALLENGE 24
43 chap_md5_generate_challenge(unsigned char *cp)
47 clen = (int)(drand48() * (MD5_MAX_CHALLENGE - MD5_MIN_CHALLENGE))
50 random_bytes(cp, clen);
54 chap_md5_verify_response(int id, char *name,
55 unsigned char *secret, int secret_len,
56 unsigned char *challenge, unsigned char *response,
57 char *message, int message_space)
59 unsigned char idbyte = id;
60 unsigned char hash[MD5_DIGEST_LENGTH];
61 unsigned int hash_len = MD5_DIGEST_LENGTH;
62 int challenge_len, response_len;
65 challenge_len = *challenge++;
66 response_len = *response++;
67 if (response_len == MD5_DIGEST_LENGTH) {
69 /* Generate hash of ID, secret, challenge */
70 PPP_MD_CTX* ctx = PPP_MD_CTX_new();
73 if (PPP_DigestInit(ctx, PPP_md5())) {
75 if (PPP_DigestUpdate(ctx, &idbyte, 1)) {
77 if (PPP_DigestUpdate(ctx, secret, secret_len)) {
79 if (PPP_DigestUpdate(ctx, challenge, challenge_len)) {
81 if (PPP_DigestFinal(ctx, hash, &hash_len)) {
92 if (success && memcmp(hash, response, hash_len) == 0) {
93 slprintf(message, message_space, "Access granted");
96 slprintf(message, message_space, "Access denied");
101 chap_md5_make_response(unsigned char *response, int id, char *our_name,
102 unsigned char *challenge, char *secret, int secret_len,
103 unsigned char *private)
105 unsigned char idbyte = id;
106 int challenge_len = *challenge++;
107 int hash_len = MD5_DIGEST_LENGTH;
110 PPP_MD_CTX* ctx = PPP_MD_CTX_new();
113 if (PPP_DigestInit(ctx, PPP_md5())) {
115 if (PPP_DigestUpdate(ctx, &idbyte, 1)) {
117 if (PPP_DigestUpdate(ctx, secret, secret_len)) {
119 if (PPP_DigestUpdate(ctx, challenge, challenge_len)) {
121 if (PPP_DigestFinal(ctx, &response[1], &hash_len)) {
123 response[0] = hash_len;
129 PPP_MD_CTX_free(ctx);
131 if (response[0] == 0)
132 warn("Error occurred in preparing CHAP-Response");
135 static struct chap_digest_type md5_digest = {
137 chap_md5_generate_challenge,
138 chap_md5_verify_response,
139 chap_md5_make_response,
140 NULL, /* check_success */
141 NULL, /* handle_failure */
147 chap_register_digest(&md5_digest);