ntlm.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "net/ntlm/ntlm.h"
  5. #include <string.h>
  6. #include "base/check_op.h"
  7. #include "base/containers/span.h"
  8. #include "base/notreached.h"
  9. #include "base/strings/utf_string_conversions.h"
  10. #include "net/base/net_string_util.h"
  11. #include "net/ntlm/ntlm_buffer_writer.h"
  12. #include "net/ntlm/ntlm_constants.h"
  13. #include "third_party/boringssl/src/include/openssl/des.h"
  14. #include "third_party/boringssl/src/include/openssl/hmac.h"
  15. #include "third_party/boringssl/src/include/openssl/md4.h"
  16. #include "third_party/boringssl/src/include/openssl/md5.h"
  17. namespace net::ntlm {
  18. namespace {
  19. // Takes the parsed target info in |av_pairs| and performs the following
  20. // actions.
  21. //
  22. // 1) If a |TargetInfoAvId::kTimestamp| AvPair exists, |server_timestamp|
  23. // is set to the payload.
  24. // 2) If |is_mic_enabled| is true, the existing |TargetInfoAvId::kFlags| AvPair
  25. // will have the |TargetInfoAvFlags::kMicPresent| bit set. If an existing
  26. // flags AvPair does not already exist, a new one is added with the value of
  27. // |TargetInfoAvFlags::kMicPresent|.
  28. // 3) If |is_epa_enabled| is true, two new AvPair entries will be added to
  29. // |av_pairs|. The first will be of type |TargetInfoAvId::kChannelBindings|
  30. // and contains MD5(|channel_bindings|) as the payload. The second will be
  31. // of type |TargetInfoAvId::kTargetName| and contains |spn| as a little
  32. // endian UTF16 string.
  33. // 4) Sets |target_info_len| to the size of |av_pairs| when serialized into
  34. // a payload.
  35. void UpdateTargetInfoAvPairs(bool is_mic_enabled,
  36. bool is_epa_enabled,
  37. const std::string& channel_bindings,
  38. const std::string& spn,
  39. std::vector<AvPair>* av_pairs,
  40. uint64_t* server_timestamp,
  41. size_t* target_info_len) {
  42. // Do a pass to update flags and calculate current length and
  43. // pull out the server timestamp if it is there.
  44. *server_timestamp = UINT64_MAX;
  45. *target_info_len = 0;
  46. bool need_flags_added = is_mic_enabled;
  47. for (AvPair& pair : *av_pairs) {
  48. *target_info_len += pair.avlen + kAvPairHeaderLen;
  49. switch (pair.avid) {
  50. case TargetInfoAvId::kFlags:
  51. // The parsing phase already set the payload to the |flags| field.
  52. if (is_mic_enabled) {
  53. pair.flags = pair.flags | TargetInfoAvFlags::kMicPresent;
  54. }
  55. need_flags_added = false;
  56. break;
  57. case TargetInfoAvId::kTimestamp:
  58. // The parsing phase already set the payload to the |timestamp| field.
  59. *server_timestamp = pair.timestamp;
  60. break;
  61. case TargetInfoAvId::kEol:
  62. case TargetInfoAvId::kChannelBindings:
  63. case TargetInfoAvId::kTargetName:
  64. // The terminator, |kEol|, should already have been removed from the
  65. // end of the list and would have been rejected if it has been inside
  66. // the list. Additionally |kChannelBindings| and |kTargetName| pairs
  67. // would have been rejected during the initial parsing. See
  68. // |NtlmBufferReader::ReadTargetInfo|.
  69. NOTREACHED();
  70. break;
  71. default:
  72. // Ignore entries we don't care about.
  73. break;
  74. }
  75. }
  76. if (need_flags_added) {
  77. DCHECK(is_mic_enabled);
  78. AvPair flags_pair(TargetInfoAvId::kFlags, sizeof(uint32_t));
  79. flags_pair.flags = TargetInfoAvFlags::kMicPresent;
  80. av_pairs->push_back(flags_pair);
  81. *target_info_len += kAvPairHeaderLen + flags_pair.avlen;
  82. }
  83. if (is_epa_enabled) {
  84. std::vector<uint8_t> channel_bindings_hash(kChannelBindingsHashLen, 0);
  85. // Hash the channel bindings if they exist otherwise they remain zeros.
  86. if (!channel_bindings.empty()) {
  87. GenerateChannelBindingHashV2(
  88. channel_bindings,
  89. base::make_span<kChannelBindingsHashLen>(channel_bindings_hash));
  90. }
  91. av_pairs->emplace_back(TargetInfoAvId::kChannelBindings,
  92. std::move(channel_bindings_hash));
  93. // Convert the SPN to little endian unicode.
  94. std::u16string spn16 = base::UTF8ToUTF16(spn);
  95. NtlmBufferWriter spn_writer(spn16.length() * 2);
  96. bool spn_writer_result =
  97. spn_writer.WriteUtf16String(spn16) && spn_writer.IsEndOfBuffer();
  98. DCHECK(spn_writer_result);
  99. av_pairs->emplace_back(TargetInfoAvId::kTargetName, spn_writer.Pass());
  100. // Add the length of the two new AV Pairs to the total length.
  101. *target_info_len +=
  102. (2 * kAvPairHeaderLen) + kChannelBindingsHashLen + (spn16.length() * 2);
  103. }
  104. // Add extra space for the terminator at the end.
  105. *target_info_len += kAvPairHeaderLen;
  106. }
  107. std::vector<uint8_t> WriteUpdatedTargetInfo(const std::vector<AvPair>& av_pairs,
  108. size_t updated_target_info_len) {
  109. bool result = true;
  110. NtlmBufferWriter writer(updated_target_info_len);
  111. for (const AvPair& pair : av_pairs) {
  112. result = writer.WriteAvPair(pair);
  113. DCHECK(result);
  114. }
  115. result = writer.WriteAvPairTerminator() && writer.IsEndOfBuffer();
  116. DCHECK(result);
  117. return writer.Pass();
  118. }
  119. // Reads 7 bytes (56 bits) from |key_56| and writes them into 8 bytes of
  120. // |key_64| with 7 bits in every byte. The least significant bits are
  121. // undefined and a subsequent operation will set those bits with a parity bit.
  122. // |key_56| must contain 7 bytes.
  123. // |key_64| must contain 8 bytes.
  124. void Splay56To64(const uint8_t* key_56, uint8_t* key_64) {
  125. key_64[0] = key_56[0];
  126. key_64[1] = key_56[0] << 7 | key_56[1] >> 1;
  127. key_64[2] = key_56[1] << 6 | key_56[2] >> 2;
  128. key_64[3] = key_56[2] << 5 | key_56[3] >> 3;
  129. key_64[4] = key_56[3] << 4 | key_56[4] >> 4;
  130. key_64[5] = key_56[4] << 3 | key_56[5] >> 5;
  131. key_64[6] = key_56[5] << 2 | key_56[6] >> 6;
  132. key_64[7] = key_56[6] << 1;
  133. }
  134. } // namespace
  135. void Create3DesKeysFromNtlmHash(
  136. base::span<const uint8_t, kNtlmHashLen> ntlm_hash,
  137. base::span<uint8_t, 24> keys) {
  138. // Put the first 112 bits from |ntlm_hash| into the first 16 bytes of
  139. // |keys|.
  140. Splay56To64(ntlm_hash.data(), keys.data());
  141. Splay56To64(ntlm_hash.data() + 7, keys.data() + 8);
  142. // Put the next 2x 7 bits in bytes 16 and 17 of |keys|, then
  143. // the last 2 bits in byte 18, then zero pad the rest of the final key.
  144. keys[16] = ntlm_hash[14];
  145. keys[17] = ntlm_hash[14] << 7 | ntlm_hash[15] >> 1;
  146. keys[18] = ntlm_hash[15] << 6;
  147. memset(keys.data() + 19, 0, 5);
  148. }
  149. void GenerateNtlmHashV1(const std::u16string& password,
  150. base::span<uint8_t, kNtlmHashLen> hash) {
  151. size_t length = password.length() * 2;
  152. NtlmBufferWriter writer(length);
  153. // The writer will handle the big endian case if necessary.
  154. bool result = writer.WriteUtf16String(password) && writer.IsEndOfBuffer();
  155. DCHECK(result);
  156. MD4(writer.GetBuffer().data(), writer.GetLength(), hash.data());
  157. }
  158. void GenerateResponseDesl(base::span<const uint8_t, kNtlmHashLen> hash,
  159. base::span<const uint8_t, kChallengeLen> challenge,
  160. base::span<uint8_t, kResponseLenV1> response) {
  161. constexpr size_t block_count = 3;
  162. constexpr size_t block_size = sizeof(DES_cblock);
  163. static_assert(kChallengeLen == block_size,
  164. "kChallengeLen must equal block_size");
  165. static_assert(kResponseLenV1 == block_count * block_size,
  166. "kResponseLenV1 must equal block_count * block_size");
  167. const DES_cblock* challenge_block =
  168. reinterpret_cast<const DES_cblock*>(challenge.data());
  169. uint8_t keys[block_count * block_size];
  170. // Map the NTLM hash to three 8 byte DES keys, with 7 bits of the key in each
  171. // byte and the least significant bit set with odd parity. Then encrypt the
  172. // 8 byte challenge with each of the three keys. This produces three 8 byte
  173. // encrypted blocks into |response|.
  174. Create3DesKeysFromNtlmHash(hash, keys);
  175. for (size_t ix = 0; ix < block_count * block_size; ix += block_size) {
  176. DES_cblock* key_block = reinterpret_cast<DES_cblock*>(keys + ix);
  177. DES_cblock* response_block =
  178. reinterpret_cast<DES_cblock*>(response.data() + ix);
  179. DES_key_schedule key_schedule;
  180. DES_set_odd_parity(key_block);
  181. DES_set_key(key_block, &key_schedule);
  182. DES_ecb_encrypt(challenge_block, response_block, &key_schedule,
  183. DES_ENCRYPT);
  184. }
  185. }
  186. void GenerateNtlmResponseV1(
  187. const std::u16string& password,
  188. base::span<const uint8_t, kChallengeLen> server_challenge,
  189. base::span<uint8_t, kResponseLenV1> ntlm_response) {
  190. uint8_t ntlm_hash[kNtlmHashLen];
  191. GenerateNtlmHashV1(password, ntlm_hash);
  192. GenerateResponseDesl(ntlm_hash, server_challenge, ntlm_response);
  193. }
  194. void GenerateResponsesV1(
  195. const std::u16string& password,
  196. base::span<const uint8_t, kChallengeLen> server_challenge,
  197. base::span<uint8_t, kResponseLenV1> lm_response,
  198. base::span<uint8_t, kResponseLenV1> ntlm_response) {
  199. GenerateNtlmResponseV1(password, server_challenge, ntlm_response);
  200. // In NTLM v1 (with LMv1 disabled), the lm_response and ntlm_response are the
  201. // same. So just copy the ntlm_response into the lm_response.
  202. memcpy(lm_response.data(), ntlm_response.data(), kResponseLenV1);
  203. }
  204. void GenerateLMResponseV1WithSessionSecurity(
  205. base::span<const uint8_t, kChallengeLen> client_challenge,
  206. base::span<uint8_t, kResponseLenV1> lm_response) {
  207. // In NTLM v1 with Session Security (aka NTLM2) the lm_response is 8 bytes of
  208. // client challenge and 16 bytes of zeros. (See 3.3.1)
  209. memcpy(lm_response.data(), client_challenge.data(), kChallengeLen);
  210. memset(lm_response.data() + kChallengeLen, 0, kResponseLenV1 - kChallengeLen);
  211. }
  212. void GenerateSessionHashV1WithSessionSecurity(
  213. base::span<const uint8_t, kChallengeLen> server_challenge,
  214. base::span<const uint8_t, kChallengeLen> client_challenge,
  215. base::span<uint8_t, kNtlmHashLen> session_hash) {
  216. MD5_CTX ctx;
  217. MD5_Init(&ctx);
  218. MD5_Update(&ctx, server_challenge.data(), kChallengeLen);
  219. MD5_Update(&ctx, client_challenge.data(), kChallengeLen);
  220. MD5_Final(session_hash.data(), &ctx);
  221. }
  222. void GenerateNtlmResponseV1WithSessionSecurity(
  223. const std::u16string& password,
  224. base::span<const uint8_t, kChallengeLen> server_challenge,
  225. base::span<const uint8_t, kChallengeLen> client_challenge,
  226. base::span<uint8_t, kResponseLenV1> ntlm_response) {
  227. // Generate the NTLMv1 Hash.
  228. uint8_t ntlm_hash[kNtlmHashLen];
  229. GenerateNtlmHashV1(password, ntlm_hash);
  230. // Generate the NTLMv1 Session Hash.
  231. uint8_t session_hash[kNtlmHashLen];
  232. GenerateSessionHashV1WithSessionSecurity(server_challenge, client_challenge,
  233. session_hash);
  234. GenerateResponseDesl(
  235. ntlm_hash, base::make_span(session_hash).subspan<0, kChallengeLen>(),
  236. ntlm_response);
  237. }
  238. void GenerateResponsesV1WithSessionSecurity(
  239. const std::u16string& password,
  240. base::span<const uint8_t, kChallengeLen> server_challenge,
  241. base::span<const uint8_t, kChallengeLen> client_challenge,
  242. base::span<uint8_t, kResponseLenV1> lm_response,
  243. base::span<uint8_t, kResponseLenV1> ntlm_response) {
  244. GenerateLMResponseV1WithSessionSecurity(client_challenge, lm_response);
  245. GenerateNtlmResponseV1WithSessionSecurity(password, server_challenge,
  246. client_challenge, ntlm_response);
  247. }
  248. void GenerateNtlmHashV2(const std::u16string& domain,
  249. const std::u16string& username,
  250. const std::u16string& password,
  251. base::span<uint8_t, kNtlmHashLen> v2_hash) {
  252. // NOTE: According to [MS-NLMP] Section 3.3.2 only the username and not the
  253. // domain is uppercased.
  254. // TODO(https://crbug.com/1051924): Using a locale-sensitive upper casing
  255. // algorithm is problematic. A more predictable approach would be to only
  256. // uppercase ASCII characters, so the hash does not change depending on the
  257. // user's locale.
  258. std::u16string upper_username;
  259. bool result = ToUpper(username, &upper_username);
  260. DCHECK(result);
  261. uint8_t v1_hash[kNtlmHashLen];
  262. GenerateNtlmHashV1(password, v1_hash);
  263. NtlmBufferWriter input_writer((upper_username.length() + domain.length()) *
  264. 2);
  265. bool writer_result = input_writer.WriteUtf16String(upper_username) &&
  266. input_writer.WriteUtf16String(domain) &&
  267. input_writer.IsEndOfBuffer();
  268. DCHECK(writer_result);
  269. unsigned int outlen = kNtlmHashLen;
  270. uint8_t* out_hash =
  271. HMAC(EVP_md5(), v1_hash, sizeof(v1_hash), input_writer.GetBuffer().data(),
  272. input_writer.GetLength(), v2_hash.data(), &outlen);
  273. DCHECK_EQ(v2_hash.data(), out_hash);
  274. DCHECK_EQ(sizeof(v1_hash), outlen);
  275. }
  276. std::vector<uint8_t> GenerateProofInputV2(
  277. uint64_t timestamp,
  278. base::span<const uint8_t, kChallengeLen> client_challenge) {
  279. NtlmBufferWriter writer(kProofInputLenV2);
  280. bool result = writer.WriteUInt16(kProofInputVersionV2) &&
  281. writer.WriteZeros(6) && writer.WriteUInt64(timestamp) &&
  282. writer.WriteBytes(client_challenge) && writer.WriteZeros(4) &&
  283. writer.IsEndOfBuffer();
  284. DCHECK(result);
  285. return writer.Pass();
  286. }
  287. void GenerateNtlmProofV2(
  288. base::span<const uint8_t, kNtlmHashLen> v2_hash,
  289. base::span<const uint8_t, kChallengeLen> server_challenge,
  290. base::span<const uint8_t, kProofInputLenV2> v2_input,
  291. base::span<const uint8_t> target_info,
  292. base::span<uint8_t, kNtlmProofLenV2> v2_proof) {
  293. bssl::ScopedHMAC_CTX ctx;
  294. HMAC_Init_ex(ctx.get(), v2_hash.data(), kNtlmHashLen, EVP_md5(), nullptr);
  295. DCHECK_EQ(kNtlmProofLenV2, HMAC_size(ctx.get()));
  296. HMAC_Update(ctx.get(), server_challenge.data(), kChallengeLen);
  297. HMAC_Update(ctx.get(), v2_input.data(), kProofInputLenV2);
  298. HMAC_Update(ctx.get(), target_info.data(), target_info.size());
  299. const uint32_t zero = 0;
  300. HMAC_Update(ctx.get(), reinterpret_cast<const uint8_t*>(&zero),
  301. sizeof(uint32_t));
  302. HMAC_Final(ctx.get(), v2_proof.data(), nullptr);
  303. }
  304. void GenerateSessionBaseKeyV2(
  305. base::span<const uint8_t, kNtlmHashLen> v2_hash,
  306. base::span<const uint8_t, kNtlmProofLenV2> v2_proof,
  307. base::span<uint8_t, kSessionKeyLenV2> session_key) {
  308. unsigned int outlen = kSessionKeyLenV2;
  309. uint8_t* result =
  310. HMAC(EVP_md5(), v2_hash.data(), kNtlmHashLen, v2_proof.data(),
  311. kNtlmProofLenV2, session_key.data(), &outlen);
  312. DCHECK_EQ(session_key.data(), result);
  313. DCHECK_EQ(kSessionKeyLenV2, outlen);
  314. }
  315. void GenerateChannelBindingHashV2(
  316. const std::string& channel_bindings,
  317. base::span<uint8_t, kNtlmHashLen> channel_bindings_hash) {
  318. NtlmBufferWriter writer(kEpaUnhashedStructHeaderLen);
  319. bool result = writer.WriteZeros(16) &&
  320. writer.WriteUInt32(channel_bindings.length()) &&
  321. writer.IsEndOfBuffer();
  322. DCHECK(result);
  323. MD5_CTX ctx;
  324. MD5_Init(&ctx);
  325. MD5_Update(&ctx, writer.GetBuffer().data(), writer.GetBuffer().size());
  326. MD5_Update(&ctx, channel_bindings.data(), channel_bindings.size());
  327. MD5_Final(channel_bindings_hash.data(), &ctx);
  328. }
  329. void GenerateMicV2(base::span<const uint8_t, kSessionKeyLenV2> session_key,
  330. base::span<const uint8_t> negotiate_msg,
  331. base::span<const uint8_t> challenge_msg,
  332. base::span<const uint8_t> authenticate_msg,
  333. base::span<uint8_t, kMicLenV2> mic) {
  334. bssl::ScopedHMAC_CTX ctx;
  335. HMAC_Init_ex(ctx.get(), session_key.data(), kSessionKeyLenV2, EVP_md5(),
  336. nullptr);
  337. DCHECK_EQ(kMicLenV2, HMAC_size(ctx.get()));
  338. HMAC_Update(ctx.get(), negotiate_msg.data(), negotiate_msg.size());
  339. HMAC_Update(ctx.get(), challenge_msg.data(), challenge_msg.size());
  340. HMAC_Update(ctx.get(), authenticate_msg.data(), authenticate_msg.size());
  341. HMAC_Final(ctx.get(), mic.data(), nullptr);
  342. }
  343. NET_EXPORT_PRIVATE std::vector<uint8_t> GenerateUpdatedTargetInfo(
  344. bool is_mic_enabled,
  345. bool is_epa_enabled,
  346. const std::string& channel_bindings,
  347. const std::string& spn,
  348. const std::vector<AvPair>& av_pairs,
  349. uint64_t* server_timestamp) {
  350. size_t updated_target_info_len = 0;
  351. std::vector<AvPair> updated_av_pairs(av_pairs);
  352. UpdateTargetInfoAvPairs(is_mic_enabled, is_epa_enabled, channel_bindings, spn,
  353. &updated_av_pairs, server_timestamp,
  354. &updated_target_info_len);
  355. return WriteUpdatedTargetInfo(updated_av_pairs, updated_target_info_len);
  356. }
  357. } // namespace net::ntlm