static void chapms2_make_response(ppp_pcb *pcb, unsigned char *response, int id, const char *our_name, const unsigned char *challenge, const char *secret, int secret_len, unsigned char *private_) { LWIP_UNUSED_ARG(id); challenge++; /* skip length, should be 16 */ *response++ = MS_CHAP2_RESPONSE_LEN; ChapMS2(pcb, challenge, #ifdef DEBUGMPPEKEY mschap2_peer_challenge, #else NULL, #endif our_name, secret, secret_len, response, private_, MS_CHAP2_AUTHENTICATEE); }
static int chapms2_verify_response(int id, char *name, unsigned char *secret, int secret_len, unsigned char *challenge, unsigned char *response, char *message, int message_space) { MS_Chap2Response *rmd; MS_Chap2Response md; char saresponse[MS_AUTH_RESPONSE_LENGTH+1]; int challenge_len, response_len; challenge_len = *challenge++; response_len = *response++; if (response_len != MS_CHAP2_RESPONSE_LEN) goto bad; rmd = (MS_Chap2Response *) response; ChapMS2(challenge, rmd->PeerChallenge, name, (char *)secret, secret_len, &md, (unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR); if (memcmp(md.NTResp, rmd->NTResp, sizeof(md.NTResp)) == 0) { if (rmd->Flags[0]) slprintf(message, message_space, "S=%s", saresponse); else slprintf(message, message_space, "S=%s M=%s", saresponse, "Access granted"); return 1; } bad: slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s", challenge_len, challenge, "Access denied"); return 0; }
static int chapms2_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 md[MS_CHAP2_RESPONSE_LEN]; char saresponse[MS_AUTH_RESPONSE_LENGTH+1]; int challenge_len, response_len; challenge_len = *challenge++; /* skip length, is 16 */ response_len = *response++; if (response_len != MS_CHAP2_RESPONSE_LEN) goto bad; /* not even the right length */ /* Generate the expected response and our mutual auth. */ 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 */ /* * Per RFC 2759, success message must be formatted as * "S=<auth_string> M=<message>" * where * <auth_string> is the Authenticator Response (mutual auth) * <message> is a text message * * However, some versions of Windows (win98 tested) do not know * about the M=<message> part (required per RFC 2759) and flag * it as an error (reported incorrectly as an encryption error * to the user). Since the RFC requires it, and it can be * useful information, we supply it if the peer is a conforming * system. Luckily (?), win98 sets the Flags field to 0x04 * (contrary to RFC requirements) so we can use that to * distinguish between conforming and non-conforming systems. * * Special thanks to Alex Swiridov <*****@*****.**> for * help debugging this. */ 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", saresponse, "Access granted"); return 1; } bad: /* * Failure message must be formatted as * "E=e R=r C=c V=v M=m" * where * e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE) * r = retry (we use 1, ok to retry) * c = challenge to use for next response, we reuse previous * v = Change Password version supported, we use 0 * m = text message * * The M=m part is only for MS-CHAPv2. Neither win2k nor * win98 (others untested) display the message to the user anyway. * They also both ignore the E=e code. * * Note that it's safe to reuse the same challenge as we don't * actually accept another response based on the error message * (and no clients try to resend a response anyway). * * Basically, this whole bit is useless code, even the small * implementation here is only because of overspecification. */ slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s", challenge_len, challenge, "Access denied"); return 0; }
static tDataBufferPtr dsauth_agent_authbuffer(tDirReference dirRef, const char *keyaccessName, u_int32_t keyaccessNameSize, const char *keyaccessPassword, u_int32_t keyaccessPasswordSize, const unsigned char *challenge) { tDataBufferPtr authDataBufPtr; u_int32_t authDataSize; char *ptr; MS_Chap2Response keyResponse; unsigned char priv[64]; authDataSize = (2 * keyaccessNameSize) + NT_RESPONSE_SIZE + (2 * CHALLENGE_SIZE) + (5 * sizeof(u_int32_t)); if ((authDataBufPtr = dsDataBufferAllocate(dirRef, authDataSize)) != 0) { authDataBufPtr->fBufferLength = authDataSize; // setup the response buffer ptr = (char *)(authDataBufPtr->fBufferData); // 4 byte length & user name *((u_int32_t*)ptr) = keyaccessNameSize; ptr += sizeof(u_int32_t); memcpy(ptr, keyaccessName, keyaccessNameSize); ptr += keyaccessNameSize; // 4 byte length & server challenge *((u_int32_t*)ptr) = CHALLENGE_SIZE; ptr += sizeof(u_int32_t); memcpy(ptr, challenge, CHALLENGE_SIZE); ptr += CHALLENGE_SIZE; // Generate MSCHAPv2 response for VPN agent as client of OD bzero(priv, sizeof(priv)); bzero(&keyResponse, sizeof(keyResponse)); ChapMS2((u_char *)challenge, NULL, (char *)keyaccessName, (u_char *)keyaccessPassword, keyaccessPasswordSize, &keyResponse, priv, MS_CHAP2_AUTHENTICATEE); #ifdef DSAUTH_DEBUG DSAuth_hex_print("VPN agent Name", keyaccessName, keyaccessNameSize); DSAuth_hex_print("Pwd", keyaccessPassword, keyaccessPasswordSize); DSAuth_hex_print("Challenge", challenge, CHALLENGE_SIZE); DSAuth_hex_print("PeerChallenge", keyResponse.PeerChallenge, CHALLENGE_SIZE); DSAuth_hex_print("response", keyResponse.NTResp, 24); #endif // 4 byte length & peer challenge *((u_int32_t*)ptr) = CHALLENGE_SIZE; ptr += sizeof(u_int32_t); memcpy(ptr, keyResponse.PeerChallenge, CHALLENGE_SIZE); ptr += CHALLENGE_SIZE; // 4 byte length & client digest *((u_int32_t*)ptr) = NT_RESPONSE_SIZE; ptr += sizeof(u_int32_t); memcpy(ptr, keyResponse.NTResp, NT_RESPONSE_SIZE); ptr += NT_RESPONSE_SIZE; // 4 byte length & user name (repeated) *((u_int32_t*)ptr) = keyaccessNameSize; ptr += sizeof(u_int32_t); memcpy(ptr, keyaccessName, keyaccessNameSize); } return authDataBufPtr; }