151
* ntpwdhash converts Unicode password to 16-byte NT hash
154
static void ntpwdhash (uint8_t *szHash, const char *szPassword)
156
char szUnicodePass[513];
161
* NT passwords are unicode. Convert plain text password
162
* to unicode by inserting a zero every other byte
164
nPasswordLen = strlen(szPassword);
165
for (i = 0; i < nPasswordLen; i++) {
166
szUnicodePass[i << 1] = szPassword[i];
167
szUnicodePass[(i << 1) + 1] = 0;
170
/* Encrypt Unicode password to a 16-byte MD4 hash */
171
fr_md4_calc(szHash, (uint8_t *) szUnicodePass, (nPasswordLen<<1) );
176
* challenge_hash() is used by mschap2() and auth_response()
177
* implements RFC2759 ChallengeHash()
178
* generates 64 bit challenge
180
static void challenge_hash( const uint8_t *peer_challenge,
181
const uint8_t *auth_challenge,
182
const char *user_name, uint8_t *challenge )
187
fr_SHA1Init(&Context);
188
fr_SHA1Update(&Context, peer_challenge, 16);
189
fr_SHA1Update(&Context, auth_challenge, 16);
190
fr_SHA1Update(&Context, (const uint8_t *) user_name,
192
fr_SHA1Final(hash, &Context);
193
memcpy(challenge, hash, 8);
197
* auth_response() generates MS-CHAP v2 SUCCESS response
198
* according to RFC 2759 GenerateAuthenticatorResponse()
199
* returns 42-octet response string
201
static void auth_response(const char *username,
202
const uint8_t *nt_hash_hash,
204
uint8_t *peer_challenge, uint8_t *auth_challenge,
208
static const uint8_t magic1[39] =
209
{0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
210
0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
211
0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
212
0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74};
214
static const uint8_t magic2[41] =
215
{0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
216
0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
217
0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
218
0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
221
static const char hex[16] = "0123456789ABCDEF";
224
uint8_t challenge[8];
227
fr_SHA1Init(&Context);
228
fr_SHA1Update(&Context, nt_hash_hash, 16);
229
fr_SHA1Update(&Context, ntresponse, 24);
230
fr_SHA1Update(&Context, magic1, 39);
231
fr_SHA1Final(digest, &Context);
232
challenge_hash(peer_challenge, auth_challenge, username, challenge);
233
fr_SHA1Init(&Context);
234
fr_SHA1Update(&Context, digest, 20);
235
fr_SHA1Update(&Context, challenge, 8);
236
fr_SHA1Update(&Context, magic2, 41);
237
fr_SHA1Final(digest, &Context);
240
* Encode the value of 'Digest' as "S=" followed by
241
* 40 ASCII hexadecimal digits and return it in
242
* AuthenticatorResponse.
244
* "S=0123456789ABCDEF0123456789ABCDEF01234567"
250
* The hexadecimal digits [A-F] MUST be uppercase.
252
for (i = 0; i < sizeof(digest); i++) {
253
response[2 + (i * 2)] = hex[(digest[i] >> 4) & 0x0f];
254
response[3 + (i * 2)] = hex[digest[i] & 0x0f];
259
131
typedef struct rlm_mschap_t {
261
133
int require_encryption;
340
219
user_name = pairfind(request->packet->vps,
342
221
if (!user_name) {
343
RDEBUG2("User-Name is required to calculateMS-CHAPv1 Challenge.");
222
RDEBUG2("User-Name is required to calculate MS-CHAPv1 Challenge.");
227
* Check for MS-CHAP-User-Name and if found, use it
228
* to construct the MSCHAPv1 challenge. This is
229
* set by rlm_eap_mschap to the MS-CHAP Response
232
* We prefer this to the User-Name in the
235
response_name = pairfind(request->packet->vps, PW_MS_CHAP_USER_NAME);
237
name_attr = response_name;
239
name_attr = user_name;
348
243
* with_ntdomain_hack moved here, too.
350
if ((username_string = strchr(user_name->vp_strvalue, '\\')) != NULL) {
245
if ((username_string = strchr(name_attr->vp_strvalue, '\\')) != NULL) {
351
246
if (inst->with_ntdomain_hack) {
352
247
username_string++;
354
249
RDEBUG2("NT Domain delimeter found, should we have enabled with_ntdomain_hack?");
355
username_string = user_name->vp_strvalue;
250
username_string = name_attr->vp_strvalue;
358
username_string = user_name->vp_strvalue;
253
username_string = name_attr->vp_strvalue;
257
((user_name->length != response_name->length) ||
258
(strncasecmp(user_name->vp_strvalue, response_name->vp_strvalue, user_name->length) != 0))) {
259
RDEBUG("WARNING: User-Name (%s) is not the same as MS-CHAP Name (%s) from EAP-MSCHAPv2", user_name->vp_strvalue, response_name->vp_strvalue);
1243
1164
return RLM_MODULE_INVALID;
1248
* with_ntdomain_hack moved here
1250
if ((username_string = strchr(username->vp_strvalue, '\\')) != NULL) {
1251
if (inst->with_ntdomain_hack) {
1168
* Check for MS-CHAP-User-Name and if found, use it
1169
* to construct the MSCHAPv1 challenge. This is
1170
* set by rlm_eap_mschap to the MS-CHAP Response
1171
* packet Name field.
1173
* We prefer this to the User-Name in the
1176
response_name = pairfind(request->packet->vps, PW_MS_CHAP_USER_NAME);
1177
if (response_name) {
1178
name_attr = response_name;
1180
name_attr = username;
1184
* with_ntdomain_hack moved here, too.
1186
if ((username_string = strchr(name_attr->vp_strvalue, '\\')) != NULL) {
1187
if (inst->with_ntdomain_hack) {
1254
RDEBUG2(" NT Domain delimeter found, should we have enabled with_ntdomain_hack?");
1255
username_string = username->vp_strvalue;
1190
RDEBUG2("NT Domain delimeter found, should we have enabled with_ntdomain_hack?");
1191
username_string = name_attr->vp_strvalue;
1258
username_string = username->vp_strvalue;
1194
username_string = name_attr->vp_strvalue;
1197
if (response_name &&
1198
((username->length != response_name->length) ||
1199
(strncasecmp(username->vp_strvalue, response_name->vp_strvalue, username->length) != 0))) {
1200
RDEBUG("ERROR: User-Name (%s) is not the same as MS-CHAP Name (%s) from EAP-MSCHAPv2", username->vp_strvalue, response_name->vp_strvalue);
1201
return RLM_MODULE_REJECT;
1261
1204
#ifdef __APPLE__