1 /* $NetBSD: chap-md5.c,v 1.5 2025/01/08 19:59:38 christos Exp $ */ 2 3 /* 4 * chap-md5.c - New CHAP/MD5 implementation. 5 * 6 * Copyright (c) 2003-2024 Paul Mackerras. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 20 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO 21 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 22 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 23 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 24 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 25 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 26 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 27 */ 28 29 #include <sys/cdefs.h> 30 __RCSID("$NetBSD: chap-md5.c,v 1.5 2025/01/08 19:59:38 christos Exp $"); 31 32 #ifdef HAVE_CONFIG_H 33 #include "config.h" 34 #endif 35 36 #include <stdlib.h> 37 #include <string.h> 38 #include "pppd-private.h" 39 #include "chap.h" 40 #include "chap-md5.h" 41 #include "magic.h" 42 #include "crypto.h" 43 44 #define MD5_MIN_CHALLENGE 16 45 #define MD5_MAX_CHALLENGE 24 46 47 static void 48 chap_md5_generate_challenge(unsigned char *cp) 49 { 50 int clen; 51 52 clen = (int)(drand48() * (MD5_MAX_CHALLENGE - MD5_MIN_CHALLENGE)) 53 + MD5_MIN_CHALLENGE; 54 *cp++ = clen; 55 random_bytes(cp, clen); 56 } 57 58 static int 59 chap_md5_verify_response(int id, char *name, 60 unsigned char *secret, int secret_len, 61 unsigned char *challenge, unsigned char *response, 62 char *message, int message_space) 63 { 64 unsigned char idbyte = id; 65 unsigned char hash[MD5_DIGEST_LENGTH]; 66 unsigned int hash_len = MD5_DIGEST_LENGTH; 67 int challenge_len, response_len; 68 bool success = 0; 69 70 challenge_len = *challenge++; 71 response_len = *response++; 72 if (response_len == MD5_DIGEST_LENGTH) { 73 74 /* Generate hash of ID, secret, challenge */ 75 PPP_MD_CTX* ctx = PPP_MD_CTX_new(); 76 if (ctx) { 77 78 if (PPP_DigestInit(ctx, PPP_md5())) { 79 80 if (PPP_DigestUpdate(ctx, &idbyte, 1)) { 81 82 if (PPP_DigestUpdate(ctx, secret, secret_len)) { 83 84 if (PPP_DigestUpdate(ctx, challenge, challenge_len)) { 85 86 if (PPP_DigestFinal(ctx, hash, &hash_len)) { 87 88 success = 1; 89 } 90 } 91 } 92 } 93 } 94 PPP_MD_CTX_free(ctx); 95 } 96 } 97 if (success && memcmp(hash, response, hash_len) == 0) { 98 slprintf(message, message_space, "Access granted"); 99 return 1; 100 } 101 slprintf(message, message_space, "Access denied"); 102 return 0; 103 } 104 105 static void 106 chap_md5_make_response(unsigned char *response, int id, char *our_name, 107 unsigned char *challenge, char *secret, int secret_len, 108 unsigned char *private) 109 { 110 unsigned char idbyte = id; 111 int challenge_len = *challenge++; 112 int hash_len = MD5_DIGEST_LENGTH; 113 114 response[0] = 0; 115 PPP_MD_CTX* ctx = PPP_MD_CTX_new(); 116 if (ctx) { 117 118 if (PPP_DigestInit(ctx, PPP_md5())) { 119 120 if (PPP_DigestUpdate(ctx, &idbyte, 1)) { 121 122 if (PPP_DigestUpdate(ctx, secret, secret_len)) { 123 124 if (PPP_DigestUpdate(ctx, challenge, challenge_len)) { 125 126 if (PPP_DigestFinal(ctx, &response[1], &hash_len)) { 127 128 response[0] = hash_len; 129 } 130 } 131 } 132 } 133 } 134 PPP_MD_CTX_free(ctx); 135 } 136 if (response[0] == 0) 137 warn("Error occurred in preparing CHAP-Response"); 138 } 139 140 static struct chap_digest_type md5_digest = { 141 CHAP_MD5, /* code */ 142 chap_md5_generate_challenge, 143 chap_md5_verify_response, 144 chap_md5_make_response, 145 NULL, /* check_success */ 146 NULL, /* handle_failure */ 147 }; 148 149 void 150 chap_md5_init(void) 151 { 152 chap_register_digest(&md5_digest); 153 } 154