mschapv2.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /*
  2. * MSCHAPV2 (RFC 2759)
  3. * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  4. *
  5. * This software may be distributed under the terms of the BSD license.
  6. * See README for more details.
  7. */
  8. #include "includes.h"
  9. #include "common.h"
  10. #include "crypto/ms_funcs.h"
  11. #include "mschapv2.h"
  12. const u8 * mschapv2_remove_domain(const u8 *username, size_t *len)
  13. {
  14. size_t i;
  15. /*
  16. * MSCHAPv2 does not include optional domain name in the
  17. * challenge-response calculation, so remove domain prefix
  18. * (if present).
  19. */
  20. for (i = 0; i < *len; i++) {
  21. if (username[i] == '\\') {
  22. *len -= i + 1;
  23. return username + i + 1;
  24. }
  25. }
  26. return username;
  27. }
  28. int mschapv2_derive_response(const u8 *identity, size_t identity_len,
  29. const u8 *password, size_t password_len,
  30. int pwhash,
  31. const u8 *auth_challenge,
  32. const u8 *peer_challenge,
  33. u8 *nt_response, u8 *auth_response,
  34. u8 *master_key)
  35. {
  36. const u8 *username;
  37. size_t username_len;
  38. u8 password_hash[16], password_hash_hash[16];
  39. wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Identity",
  40. identity, identity_len);
  41. username_len = identity_len;
  42. username = mschapv2_remove_domain(identity, &username_len);
  43. wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Username",
  44. username, username_len);
  45. wpa_hexdump(MSG_DEBUG, "MSCHAPV2: auth_challenge",
  46. auth_challenge, MSCHAPV2_CHAL_LEN);
  47. wpa_hexdump(MSG_DEBUG, "MSCHAPV2: peer_challenge",
  48. peer_challenge, MSCHAPV2_CHAL_LEN);
  49. wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: username",
  50. username, username_len);
  51. /* Authenticator response is not really needed yet, but calculate it
  52. * here so that challenges need not be saved. */
  53. if (pwhash) {
  54. wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: password hash",
  55. password, password_len);
  56. if (generate_nt_response_pwhash(auth_challenge, peer_challenge,
  57. username, username_len,
  58. password, nt_response) ||
  59. generate_authenticator_response_pwhash(
  60. password, peer_challenge, auth_challenge,
  61. username, username_len, nt_response,
  62. auth_response))
  63. return -1;
  64. } else {
  65. wpa_hexdump_ascii_key(MSG_DEBUG, "MSCHAPV2: password",
  66. password, password_len);
  67. if (generate_nt_response(auth_challenge, peer_challenge,
  68. username, username_len,
  69. password, password_len,
  70. nt_response) ||
  71. generate_authenticator_response(password, password_len,
  72. peer_challenge,
  73. auth_challenge,
  74. username, username_len,
  75. nt_response,
  76. auth_response))
  77. return -1;
  78. }
  79. wpa_hexdump(MSG_DEBUG, "MSCHAPV2: NT Response",
  80. nt_response, MSCHAPV2_NT_RESPONSE_LEN);
  81. wpa_hexdump(MSG_DEBUG, "MSCHAPV2: Auth Response",
  82. auth_response, MSCHAPV2_AUTH_RESPONSE_LEN);
  83. /* Generate master_key here since we have the needed data available. */
  84. if (pwhash) {
  85. if (hash_nt_password_hash(password, password_hash_hash))
  86. return -1;
  87. } else {
  88. if (nt_password_hash(password, password_len, password_hash) ||
  89. hash_nt_password_hash(password_hash, password_hash_hash))
  90. return -1;
  91. }
  92. if (get_master_key(password_hash_hash, nt_response, master_key))
  93. return -1;
  94. wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: Master Key",
  95. master_key, MSCHAPV2_MASTER_KEY_LEN);
  96. return 0;
  97. }
  98. int mschapv2_verify_auth_response(const u8 *auth_response,
  99. const u8 *buf, size_t buf_len)
  100. {
  101. u8 recv_response[MSCHAPV2_AUTH_RESPONSE_LEN];
  102. if (buf_len < 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN ||
  103. buf[0] != 'S' || buf[1] != '=' ||
  104. hexstr2bin((char *) (buf + 2), recv_response,
  105. MSCHAPV2_AUTH_RESPONSE_LEN) ||
  106. os_memcmp_const(auth_response, recv_response,
  107. MSCHAPV2_AUTH_RESPONSE_LEN) != 0)
  108. return -1;
  109. return 0;
  110. }