summaryrefslogtreecommitdiff
path: root/chromium/net/ntlm
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-09-18 14:34:04 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-10-04 11:15:27 +0000
commite6430e577f105ad8813c92e75c54660c4985026e (patch)
tree88115e5d1fb471fea807111924dcccbeadbf9e4f /chromium/net/ntlm
parent53d399fe6415a96ea6986ec0d402a9c07da72453 (diff)
downloadqtwebengine-chromium-e6430e577f105ad8813c92e75c54660c4985026e.tar.gz
BASELINE: Update Chromium to 61.0.3163.99
Change-Id: I8452f34574d88ca2b27af9bd56fc9ff3f16b1367 Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/net/ntlm')
-rw-r--r--chromium/net/ntlm/OWNERS6
-rw-r--r--chromium/net/ntlm/des.cc88
-rw-r--r--chromium/net/ntlm/des.h31
-rw-r--r--chromium/net/ntlm/des_unittest.cc46
-rw-r--r--chromium/net/ntlm/md4.cc185
-rw-r--r--chromium/net/ntlm/md4.h74
-rw-r--r--chromium/net/ntlm/ntlm.cc125
-rw-r--r--chromium/net/ntlm/ntlm.h131
-rw-r--r--chromium/net/ntlm/ntlm_buffer_reader.cc179
-rw-r--r--chromium/net/ntlm/ntlm_buffer_reader.h191
-rw-r--r--chromium/net/ntlm/ntlm_buffer_reader_unittest.cc367
-rw-r--r--chromium/net/ntlm/ntlm_buffer_writer.cc152
-rw-r--r--chromium/net/ntlm/ntlm_buffer_writer.h177
-rw-r--r--chromium/net/ntlm/ntlm_buffer_writer_unittest.cc235
-rw-r--r--chromium/net/ntlm/ntlm_constants.h91
-rw-r--r--chromium/net/ntlm/ntlm_test_data.h81
-rw-r--r--chromium/net/ntlm/ntlm_unittest.cc120
17 files changed, 2279 insertions, 0 deletions
diff --git a/chromium/net/ntlm/OWNERS b/chromium/net/ntlm/OWNERS
new file mode 100644
index 00000000000..156ce37c4df
--- /dev/null
+++ b/chromium/net/ntlm/OWNERS
@@ -0,0 +1,6 @@
+asanka@chromium.org
+rsleevi@chromium.org
+zentaro@chromium.org
+
+# COMPONENT: Internals>Network>Auth
+# TEAM: net-dev@chromium.org
diff --git a/chromium/net/ntlm/des.cc b/chromium/net/ntlm/des.cc
new file mode 100644
index 00000000000..1967f66c8dc
--- /dev/null
+++ b/chromium/net/ntlm/des.cc
@@ -0,0 +1,88 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/ntlm/des.h"
+
+#include "base/logging.h"
+#include "crypto/openssl_util.h"
+#include "third_party/boringssl/src/include/openssl/des.h"
+
+// The iOS version of DESEncrypt is our own code.
+// DESSetKeyParity and DESMakeKey are based on
+// mozilla/security/manager/ssl/src/nsNTLMAuthModule.cpp, CVS rev. 1.14.
+/* clang-format off */
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla.
+ *
+ * The Initial Developer of the Original Code is IBM Corporation.
+ * Portions created by IBM Corporation are Copyright (C) 2003
+ * IBM Corporation. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@meer.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// Set odd parity bit (in least significant bit position).
+static uint8_t DESSetKeyParity(uint8_t x) {
+ if ((((x >> 7) ^ (x >> 6) ^ (x >> 5) ^
+ (x >> 4) ^ (x >> 3) ^ (x >> 2) ^
+ (x >> 1)) & 0x01) == 0) {
+ x |= 0x01;
+ } else {
+ x &= 0xfe;
+ }
+ return x;
+}
+
+namespace net {
+
+void DESMakeKey(const uint8_t* raw, uint8_t* key) {
+ key[0] = DESSetKeyParity(raw[0]);
+ key[1] = DESSetKeyParity((raw[0] << 7) | (raw[1] >> 1));
+ key[2] = DESSetKeyParity((raw[1] << 6) | (raw[2] >> 2));
+ key[3] = DESSetKeyParity((raw[2] << 5) | (raw[3] >> 3));
+ key[4] = DESSetKeyParity((raw[3] << 4) | (raw[4] >> 4));
+ key[5] = DESSetKeyParity((raw[4] << 3) | (raw[5] >> 5));
+ key[6] = DESSetKeyParity((raw[5] << 2) | (raw[6] >> 6));
+ key[7] = DESSetKeyParity((raw[6] << 1));
+}
+
+void DESEncrypt(const uint8_t* key, const uint8_t* src, uint8_t* hash) {
+ crypto::EnsureOpenSSLInit();
+
+ DES_key_schedule ks;
+ DES_set_key(
+ reinterpret_cast<const DES_cblock*>(key), &ks);
+
+ DES_ecb_encrypt(reinterpret_cast<const DES_cblock*>(src),
+ reinterpret_cast<DES_cblock*>(hash), &ks, DES_ENCRYPT);
+}
+
+} // namespace net
diff --git a/chromium/net/ntlm/des.h b/chromium/net/ntlm/des.h
new file mode 100644
index 00000000000..8540d62803b
--- /dev/null
+++ b/chromium/net/ntlm/des.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_HTTP_DES_H_
+#define NET_HTTP_DES_H_
+
+#include <stdint.h>
+
+#include "net/base/net_export.h"
+
+namespace net {
+
+//-----------------------------------------------------------------------------
+// DES support code for NTLM authentication.
+//
+// TODO(wtc): Turn this into a C++ API and move it to the base module.
+
+// Build a 64-bit DES key from a 56-bit raw key.
+NET_EXPORT_PRIVATE void DESMakeKey(const uint8_t* raw, uint8_t* key);
+
+// Run the DES encryption algorithm in ECB mode on one block (8 bytes) of
+// data. |key| is a DES key (8 bytes), |src| is the input plaintext (8
+// bytes), and |hash| is an 8-byte buffer receiving the output ciphertext.
+NET_EXPORT_PRIVATE void DESEncrypt(const uint8_t* key,
+ const uint8_t* src,
+ uint8_t* hash);
+
+} // namespace net
+
+#endif // NET_HTTP_DES_H_
diff --git a/chromium/net/ntlm/des_unittest.cc b/chromium/net/ntlm/des_unittest.cc
new file mode 100644
index 00000000000..d1f9ae5afe7
--- /dev/null
+++ b/chromium/net/ntlm/des_unittest.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string.h>
+
+#include "net/ntlm/des.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+// This test vector comes from the NSS FIPS power-up self-test.
+TEST(DESTest, KnownAnswerTest1) {
+ // DES known key (56-bits).
+ static const uint8_t des_known_key[] = "ANSI DES";
+
+ // DES known plaintext (64-bits).
+ static const uint8_t des_ecb_known_plaintext[] = "Netscape";
+
+ // DES known ciphertext (64-bits).
+ static const uint8_t des_ecb_known_ciphertext[] = {0x26, 0x14, 0xe9, 0xc3,
+ 0x28, 0x80, 0x50, 0xb0};
+
+ uint8_t ciphertext[8];
+ memset(ciphertext, 0xaf, sizeof(ciphertext));
+
+ DESEncrypt(des_known_key, des_ecb_known_plaintext, ciphertext);
+ EXPECT_EQ(0, memcmp(ciphertext, des_ecb_known_ciphertext, 8));
+}
+
+// This test vector comes from NIST Special Publication 800-17, Modes of
+// Operation Validation System (MOVS): Requirements and Procedures, Appendix
+// A, page 124.
+TEST(DESTest, KnownAnswerTest2) {
+ static const uint8_t key[] = {0x10, 0x31, 0x6e, 0x02, 0x8c, 0x8f, 0x3b, 0x4a};
+ static const uint8_t plaintext[] = {0, 0, 0, 0, 0, 0, 0, 0};
+ static const uint8_t known_ciphertext[] = {0x82, 0xdc, 0xba, 0xfb,
+ 0xde, 0xab, 0x66, 0x02};
+ uint8_t ciphertext[8];
+ memset(ciphertext, 0xaf, sizeof(ciphertext));
+
+ DESEncrypt(key, plaintext, ciphertext);
+ EXPECT_EQ(0, memcmp(ciphertext, known_ciphertext, 8));
+}
+
+} // namespace net
diff --git a/chromium/net/ntlm/md4.cc b/chromium/net/ntlm/md4.cc
new file mode 100644
index 00000000000..cd18e9fd88e
--- /dev/null
+++ b/chromium/net/ntlm/md4.cc
@@ -0,0 +1,185 @@
+// This is mozilla/security/manager/ssl/src/md4.c, CVS rev. 1.1, with trivial
+// changes to port it to our source tree.
+//
+// WARNING: MD4 is cryptographically weak. Do not use MD4 except in NTLM
+// authentication.
+
+/* clang-format off */
+/* vim:set ts=2 sw=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla.
+ *
+ * The Initial Developer of the Original Code is IBM Corporation.
+ * Portions created by IBM Corporation are Copyright (C) 2003
+ * IBM Corporation. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@meer.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * "clean room" MD4 implementation (see RFC 1320)
+ */
+
+#include "net/ntlm/md4.h"
+
+#include <string.h>
+
+typedef uint32_t Uint32;
+typedef uint8_t Uint8;
+
+/* the "conditional" function */
+#define F(x,y,z) (((x) & (y)) | (~(x) & (z)))
+
+/* the "majority" function */
+#define G(x,y,z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+
+/* the "parity" function */
+#define H(x,y,z) ((x) ^ (y) ^ (z))
+
+/* rotate n-bits to the left */
+#define ROTL(x,n) (((x) << (n)) | ((x) >> (0x20 - n)))
+
+/* round 1: [abcd k s]: a = (a + F(b,c,d) + X[k]) <<< s */
+#define RD1(a,b,c,d,k,s) a += F(b,c,d) + X[k]; a = ROTL(a,s)
+
+/* round 2: [abcd k s]: a = (a + G(b,c,d) + X[k] + MAGIC) <<< s */
+#define RD2(a,b,c,d,k,s) a += G(b,c,d) + X[k] + 0x5A827999; a = ROTL(a,s)
+
+/* round 3: [abcd k s]: a = (a + H(b,c,d) + X[k] + MAGIC) <<< s */
+#define RD3(a,b,c,d,k,s) a += H(b,c,d) + X[k] + 0x6ED9EBA1; a = ROTL(a,s)
+
+/* converts from word array to byte array, len is number of bytes */
+static void w2b(Uint8 *out, const Uint32 *in, Uint32 len)
+{
+ Uint8 *bp; const Uint32 *wp, *wpend;
+
+ bp = out;
+ wp = in;
+ wpend = wp + (len >> 2);
+
+ for (; wp != wpend; ++wp, bp += 4)
+ {
+ bp[0] = (Uint8) ((*wp ) & 0xFF);
+ bp[1] = (Uint8) ((*wp >> 8) & 0xFF);
+ bp[2] = (Uint8) ((*wp >> 16) & 0xFF);
+ bp[3] = (Uint8) ((*wp >> 24) & 0xFF);
+ }
+}
+
+/* converts from byte array to word array, len is number of bytes */
+static void b2w(Uint32 *out, const Uint8 *in, Uint32 len)
+{
+ Uint32 *wp; const Uint8 *bp, *bpend;
+
+ wp = out;
+ bp = in;
+ bpend = in + len;
+
+ for (; bp != bpend; bp += 4, ++wp)
+ {
+ *wp = (Uint32) (bp[0] ) |
+ (Uint32) (bp[1] << 8) |
+ (Uint32) (bp[2] << 16) |
+ (Uint32) (bp[3] << 24);
+ }
+}
+
+/* update state: data is 64 bytes in length */
+static void md4step(Uint32 state[4], const Uint8 *data)
+{
+ Uint32 A, B, C, D, X[16];
+
+ b2w(X, data, 64);
+
+ A = state[0];
+ B = state[1];
+ C = state[2];
+ D = state[3];
+
+ RD1(A,B,C,D, 0,3); RD1(D,A,B,C, 1,7); RD1(C,D,A,B, 2,11); RD1(B,C,D,A, 3,19);
+ RD1(A,B,C,D, 4,3); RD1(D,A,B,C, 5,7); RD1(C,D,A,B, 6,11); RD1(B,C,D,A, 7,19);
+ RD1(A,B,C,D, 8,3); RD1(D,A,B,C, 9,7); RD1(C,D,A,B,10,11); RD1(B,C,D,A,11,19);
+ RD1(A,B,C,D,12,3); RD1(D,A,B,C,13,7); RD1(C,D,A,B,14,11); RD1(B,C,D,A,15,19);
+
+ RD2(A,B,C,D, 0,3); RD2(D,A,B,C, 4,5); RD2(C,D,A,B, 8, 9); RD2(B,C,D,A,12,13);
+ RD2(A,B,C,D, 1,3); RD2(D,A,B,C, 5,5); RD2(C,D,A,B, 9, 9); RD2(B,C,D,A,13,13);
+ RD2(A,B,C,D, 2,3); RD2(D,A,B,C, 6,5); RD2(C,D,A,B,10, 9); RD2(B,C,D,A,14,13);
+ RD2(A,B,C,D, 3,3); RD2(D,A,B,C, 7,5); RD2(C,D,A,B,11, 9); RD2(B,C,D,A,15,13);
+
+ RD3(A,B,C,D, 0,3); RD3(D,A,B,C, 8,9); RD3(C,D,A,B, 4,11); RD3(B,C,D,A,12,15);
+ RD3(A,B,C,D, 2,3); RD3(D,A,B,C,10,9); RD3(C,D,A,B, 6,11); RD3(B,C,D,A,14,15);
+ RD3(A,B,C,D, 1,3); RD3(D,A,B,C, 9,9); RD3(C,D,A,B, 5,11); RD3(B,C,D,A,13,15);
+ RD3(A,B,C,D, 3,3); RD3(D,A,B,C,11,9); RD3(C,D,A,B, 7,11); RD3(B,C,D,A,15,15);
+
+ state[0] += A;
+ state[1] += B;
+ state[2] += C;
+ state[3] += D;
+}
+
+namespace net {
+namespace weak_crypto {
+
+void MD4Sum(const Uint8 *input, Uint32 inputLen, Uint8 *result)
+{
+ Uint8 final[128];
+ Uint32 i, n, m, state[4];
+
+ /* magic initial states */
+ state[0] = 0x67452301;
+ state[1] = 0xEFCDAB89;
+ state[2] = 0x98BADCFE;
+ state[3] = 0x10325476;
+
+ /* compute number of complete 64-byte segments contained in input */
+ m = inputLen >> 6;
+
+ /* digest first m segments */
+ for (i=0; i<m; ++i)
+ md4step(state, (input + (i << 6)));
+
+ /* build final buffer */
+ n = inputLen % 64;
+ memcpy(final, input + (m << 6), n);
+ final[n] = 0x80;
+ memset(final + n + 1, 0, 120 - (n + 1));
+
+ inputLen = inputLen << 3;
+ w2b(final + (n >= 56 ? 120 : 56), &inputLen, 4);
+
+ md4step(state, final);
+ if (n >= 56)
+ md4step(state, final + 64);
+
+ /* copy state to result */
+ w2b(result, state, 16);
+}
+
+} // namespace weak_crypto
+} // namespace net
diff --git a/chromium/net/ntlm/md4.h b/chromium/net/ntlm/md4.h
new file mode 100644
index 00000000000..4d37a643533
--- /dev/null
+++ b/chromium/net/ntlm/md4.h
@@ -0,0 +1,74 @@
+// This is mozilla/security/manager/ssl/src/md4.h, CVS rev. 1.1, with trivial
+// changes to port it to our source tree.
+//
+// WARNING: MD4 is cryptographically weak. Do not use MD4 except in NTLM
+// authentication.
+
+/* vim:set ts=2 sw=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla.
+ *
+ * The Initial Developer of the Original Code is IBM Corporation.
+ * Portions created by IBM Corporation are Copyright (C) 2003
+ * IBM Corporation. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@meer.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef NET_HTTP_MD4_H_
+#define NET_HTTP_MD4_H_
+
+#include <stdint.h>
+
+namespace net {
+namespace weak_crypto {
+
+/**
+ * MD4Sum - computes the MD4 sum over the input buffer per RFC 1320
+ *
+ * @param input
+ * buffer containing input data
+ * @param inputLen
+ * length of input buffer (number of bytes)
+ * @param result
+ * 16-byte buffer that will contain the MD4 sum upon return
+ *
+ * NOTE: MD4 is superceded by MD5. do not use MD4 unless required by the
+ * protocol you are implementing (e.g., NTLM requires MD4).
+ *
+ * NOTE: this interface is designed for relatively small buffers. A streaming
+ * interface would make more sense if that were a requirement. Currently, this
+ * is good enough for the applications we care about.
+ */
+void MD4Sum(const uint8_t* input, uint32_t inputLen, uint8_t* result);
+
+} // namespace weak_crypto
+} // namespace net
+
+#endif // NET_HTTP_MD4_H_
diff --git a/chromium/net/ntlm/ntlm.cc b/chromium/net/ntlm/ntlm.cc
new file mode 100644
index 00000000000..14cc4bcdf64
--- /dev/null
+++ b/chromium/net/ntlm/ntlm.cc
@@ -0,0 +1,125 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/ntlm/ntlm.h"
+
+#include <string.h>
+
+#include "base/logging.h"
+#include "base/md5.h"
+#include "net/ntlm/des.h"
+#include "net/ntlm/md4.h"
+#include "net/ntlm/ntlm_buffer_writer.h"
+
+namespace net {
+namespace ntlm {
+
+void GenerateNtlmHashV1(const base::string16& password, uint8_t* hash) {
+ size_t length = password.length() * 2;
+ NtlmBufferWriter writer(length);
+
+ // The writer will handle the big endian case if necessary.
+ bool result = writer.WriteUtf16String(password);
+ DCHECK(result);
+
+ weak_crypto::MD4Sum(
+ reinterpret_cast<const uint8_t*>(writer.GetBuffer().data()), length,
+ hash);
+}
+
+void GenerateResponseDesl(const uint8_t* hash,
+ const uint8_t* challenge,
+ uint8_t* response) {
+ // See DESL(K, D) function in [MS-NLMP] Section 6
+ uint8_t key1[8];
+ uint8_t key2[8];
+ uint8_t key3[8];
+
+ // The last 2 bytes of the hash are zero padded (5 zeros) as the
+ // input to generate key3.
+ uint8_t padded_hash[7];
+ padded_hash[0] = hash[14];
+ padded_hash[1] = hash[15];
+ memset(padded_hash + 2, 0, 5);
+
+ DESMakeKey(hash, key1);
+ DESMakeKey(hash + 7, key2);
+ DESMakeKey(padded_hash, key3);
+
+ DESEncrypt(key1, challenge, response);
+ DESEncrypt(key2, challenge, response + 8);
+ DESEncrypt(key3, challenge, response + 16);
+}
+
+void GenerateNtlmResponseV1(const base::string16& password,
+ const uint8_t* challenge,
+ uint8_t* ntlm_response) {
+ uint8_t ntlm_hash[kNtlmHashLen];
+ GenerateNtlmHashV1(password, ntlm_hash);
+ GenerateResponseDesl(ntlm_hash, challenge, ntlm_response);
+}
+
+void GenerateResponsesV1(const base::string16& password,
+ const uint8_t* server_challenge,
+ uint8_t* lm_response,
+ uint8_t* ntlm_response) {
+ GenerateNtlmResponseV1(password, server_challenge, ntlm_response);
+
+ // In NTLM v1 (with LMv1 disabled), the lm_response and ntlm_response are the
+ // same. So just copy the ntlm_response into the lm_response.
+ memcpy(lm_response, ntlm_response, kResponseLenV1);
+}
+
+void GenerateLMResponseV1WithSessionSecurity(const uint8_t* client_challenge,
+ uint8_t* lm_response) {
+ // In NTLM v1 with Session Security (aka NTLM2) the lm_response is 8 bytes of
+ // client challenge and 16 bytes of zeros. (See 3.3.1)
+ memcpy(lm_response, client_challenge, kChallengeLen);
+ memset(lm_response + kChallengeLen, 0, kResponseLenV1 - kChallengeLen);
+}
+
+void GenerateSessionHashV1WithSessionSecurity(const uint8_t* server_challenge,
+ const uint8_t* client_challenge,
+ base::MD5Digest* session_hash) {
+ base::MD5Context ctx;
+ base::MD5Init(&ctx);
+ base::MD5Update(
+ &ctx, base::StringPiece(reinterpret_cast<const char*>(server_challenge),
+ kChallengeLen));
+ base::MD5Update(
+ &ctx, base::StringPiece(reinterpret_cast<const char*>(client_challenge),
+ kChallengeLen));
+
+ base::MD5Final(session_hash, &ctx);
+}
+
+void GenerateNtlmResponseV1WithSessionSecurity(const base::string16& password,
+ const uint8_t* server_challenge,
+ const uint8_t* client_challenge,
+ uint8_t* ntlm_response) {
+ // Generate the NTLMv1 Hash.
+ uint8_t ntlm_hash[kNtlmHashLen];
+ GenerateNtlmHashV1(password, ntlm_hash);
+
+ // Generate the NTLMv1 Session Hash.
+ base::MD5Digest session_hash;
+ GenerateSessionHashV1WithSessionSecurity(server_challenge, client_challenge,
+ &session_hash);
+
+ // Only the first 8 bytes of |session_hash.a| are actually used.
+ GenerateResponseDesl(ntlm_hash, session_hash.a, ntlm_response);
+}
+
+void GenerateResponsesV1WithSessionSecurity(const base::string16& password,
+ const uint8_t* server_challenge,
+ const uint8_t* client_challenge,
+ uint8_t* lm_response,
+ uint8_t* ntlm_response) {
+ GenerateLMResponseV1WithSessionSecurity(client_challenge, lm_response);
+ GenerateNtlmResponseV1WithSessionSecurity(password, server_challenge,
+ client_challenge, ntlm_response);
+}
+
+} // namespace ntlm
+} // namespace net
diff --git a/chromium/net/ntlm/ntlm.h b/chromium/net/ntlm/ntlm.h
new file mode 100644
index 00000000000..1d98611e66d
--- /dev/null
+++ b/chromium/net/ntlm/ntlm.h
@@ -0,0 +1,131 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Based on [MS-NLMP]: NT LAN Manager (NTLM) Authentication Protocol
+// Specification version 28.0 [1]. Additional NTLM reference [2].
+//
+// [1] https://msdn.microsoft.com/en-us/library/cc236621.aspx
+// [2] http://davenport.sourceforge.net/ntlm.html
+
+#ifndef NET_BASE_NTLM_H_
+#define NET_BASE_NTLM_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/ntlm/ntlm_constants.h"
+
+namespace base {
+struct MD5Digest;
+}
+
+namespace net {
+namespace ntlm {
+
+// Generates the NTLMv1 Hash and writes the |kNtlmHashLen| byte result to
+// |hash|. Defined by NTOWFv1() in [MS-NLMP] Section 3.3.1.
+NET_EXPORT_PRIVATE void GenerateNtlmHashV1(const base::string16& password,
+ uint8_t* hash);
+
+// Generates the |kResponseLenV1| byte NTLMv1 response field according to the
+// DESL(K, V) function in [MS-NLMP] Section 6.
+//
+// |hash| must contain |kNtlmHashLen| bytes.
+// |challenge| must contain |kChallengeLen| bytes.
+// |response| must contain |kResponseLenV1| bytes.
+NET_EXPORT_PRIVATE void GenerateResponseDesl(const uint8_t* hash,
+ const uint8_t* challenge,
+ uint8_t* response);
+
+// Generates the NTLM Response field for NTLMv1 without extended session
+// security. Defined by ComputeResponse() in [MS-NLMP] Section 3.3.1 for the
+// case where NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY is not set.
+//
+// |server_challenge| must contain |kChallengeLen| bytes.
+// |ntlm_response| must contain |kResponseLenV1| bytes.
+NET_EXPORT_PRIVATE void GenerateNtlmResponseV1(const base::string16& password,
+ const uint8_t* server_challenge,
+ uint8_t* ntlm_response);
+
+// Generates both the LM Response and NTLM Response fields for NTLMv1 based
+// on the users password and the servers challenge. Both the LM and NTLM
+// Response are the result of |GenerateNtlmResponseV1|.
+//
+// NOTE: This should not be used. The default flags always include session
+// security. Session security can however be disabled in NTLMv1 by omitting
+// NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY from the flag set used to
+// initialize |NtlmClient|.
+//
+// The default flags include this flag and the client will not be
+// downgraded by the server.
+//
+// |server_challenge| must contain |kChallengeLen| bytes.
+// |lm_response| must contain |kResponseLenV1| bytes.
+// |ntlm_response| must contain |kResponseLenV1| bytes.
+NET_EXPORT_PRIVATE void GenerateResponsesV1(const base::string16& password,
+ const uint8_t* server_challenge,
+ uint8_t* lm_response,
+ uint8_t* ntlm_response);
+
+// The LM Response in V1 with extended session security is 8 bytes of the
+// |client_challenge| then 16 bytes of zero. This is the value
+// LmChallengeResponse in ComputeResponse() when
+// NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY is set. See [MS-NLMP] Section
+// 3.3.1.
+//
+// |lm_response| must contain |kResponseLenV1| bytes.
+NET_EXPORT_PRIVATE void GenerateLMResponseV1WithSessionSecurity(
+ const uint8_t* client_challenge,
+ uint8_t* lm_response);
+
+// The |session_hash| is MD5(CONCAT(server_challenge, client_challenge)).
+// It is used instead of just |server_challenge| in NTLMv1 when
+// NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY is set. See [MS-NLMP] Section
+// 3.3.1.
+//
+// |server_challenge| must contain |kChallengeLen| bytes.
+// |client_challenge| must contain |kChallengeLen| bytes.
+NET_EXPORT_PRIVATE void GenerateSessionHashV1WithSessionSecurity(
+ const uint8_t* server_challenge,
+ const uint8_t* client_challenge,
+ base::MD5Digest* session_hash);
+
+// Generates the NTLM Response for NTLMv1 with session security.
+// Defined by ComputeResponse() in [MS-NLMP] Section 3.3.1 for the
+// case where NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY is set.
+//
+// |server_challenge| must contain |kChallengeLen| bytes.
+// |client_challenge| must contain |kChallengeLen| bytes.
+// |ntlm_response| must contain |kResponseLenV1| bytes.
+NET_EXPORT_PRIVATE void GenerateNtlmResponseV1WithSessionSecurity(
+ const base::string16& password,
+ const uint8_t* server_challenge,
+ const uint8_t* client_challenge,
+ uint8_t* ntlm_response);
+
+// Generates the responses for V1 with extended session security.
+// This is also known as NTLM2 (which is not the same as NTLMv2).
+// |lm_response| is the result of |GenerateLMResponseV1WithSessionSecurity| and
+// |ntlm_response| is the result of |GenerateNtlmResponseV1WithSessionSecurity|.
+// See [MS-NLMP] Section 3.3.1.
+//
+// |server_challenge| must contain |kChallengeLen| bytes.
+// |client_challenge| must contain |kChallengeLen| bytes.
+// |ntlm_response| must contain |kResponseLenV1| bytes.
+NET_EXPORT_PRIVATE void GenerateResponsesV1WithSessionSecurity(
+ const base::string16& password,
+ const uint8_t* server_challenge,
+ const uint8_t* client_challenge,
+ uint8_t* lm_response,
+ uint8_t* ntlm_response);
+
+} // namespace ntlm
+} // namespace net
+
+#endif // NET_BASE_NTLM_H_
diff --git a/chromium/net/ntlm/ntlm_buffer_reader.cc b/chromium/net/ntlm/ntlm_buffer_reader.cc
new file mode 100644
index 00000000000..95ae2e6ee43
--- /dev/null
+++ b/chromium/net/ntlm/ntlm_buffer_reader.cc
@@ -0,0 +1,179 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/ntlm/ntlm_buffer_reader.h"
+
+#include <string.h>
+
+#include "base/logging.h"
+
+namespace net {
+namespace ntlm {
+
+NtlmBufferReader::NtlmBufferReader(base::StringPiece buffer)
+ : buffer_(buffer), cursor_(0) {
+ DCHECK(buffer.data());
+}
+
+NtlmBufferReader::NtlmBufferReader(const uint8_t* ptr, size_t len)
+ : NtlmBufferReader(
+ base::StringPiece(reinterpret_cast<const char*>(ptr), len)) {}
+
+NtlmBufferReader::~NtlmBufferReader() {}
+
+bool NtlmBufferReader::CanRead(size_t len) const {
+ return CanReadFrom(GetCursor(), len);
+}
+
+bool NtlmBufferReader::CanReadFrom(size_t offset, size_t len) const {
+ if (len == 0)
+ return true;
+
+ return (len <= GetLength() && offset <= GetLength() - len);
+}
+
+bool NtlmBufferReader::ReadUInt16(uint16_t* value) {
+ return ReadUInt<uint16_t>(value);
+}
+
+bool NtlmBufferReader::ReadUInt32(uint32_t* value) {
+ return ReadUInt<uint32_t>(value);
+}
+
+bool NtlmBufferReader::ReadUInt64(uint64_t* value) {
+ return ReadUInt<uint64_t>(value);
+}
+
+bool NtlmBufferReader::ReadFlags(NegotiateFlags* flags) {
+ uint32_t raw;
+ if (!ReadUInt32(&raw))
+ return false;
+
+ *flags = static_cast<NegotiateFlags>(raw);
+ return true;
+}
+
+bool NtlmBufferReader::ReadBytes(uint8_t* buffer, size_t len) {
+ if (!CanRead(len))
+ return false;
+
+ memcpy(reinterpret_cast<void*>(buffer),
+ reinterpret_cast<const void*>(GetBufferAtCursor()), len);
+
+ AdvanceCursor(len);
+ return true;
+}
+
+bool NtlmBufferReader::ReadBytesFrom(const SecurityBuffer& sec_buf,
+ uint8_t* buffer) {
+ if (!CanReadFrom(sec_buf))
+ return false;
+
+ memcpy(reinterpret_cast<void*>(buffer),
+ reinterpret_cast<const void*>(GetBufferPtr() + sec_buf.offset),
+ sec_buf.length);
+
+ return true;
+}
+
+bool NtlmBufferReader::ReadSecurityBuffer(SecurityBuffer* sec_buf) {
+ return ReadUInt16(&sec_buf->length) && SkipBytes(sizeof(uint16_t)) &&
+ ReadUInt32(&sec_buf->offset);
+}
+
+bool NtlmBufferReader::ReadMessageType(MessageType* message_type) {
+ uint32_t raw_message_type;
+ if (!ReadUInt32(&raw_message_type))
+ return false;
+
+ *message_type = static_cast<MessageType>(raw_message_type);
+
+ if (*message_type != MessageType::kNegotiate &&
+ *message_type != MessageType::kChallenge &&
+ *message_type != MessageType::kAuthenticate)
+ return false;
+
+ return true;
+}
+
+bool NtlmBufferReader::SkipSecurityBuffer() {
+ return SkipBytes(kSecurityBufferLen);
+}
+
+bool NtlmBufferReader::SkipSecurityBufferWithValidation() {
+ SecurityBuffer sec_buf;
+ return ReadSecurityBuffer(&sec_buf) && CanReadFrom(sec_buf);
+}
+
+bool NtlmBufferReader::SkipBytes(size_t count) {
+ if (!CanRead(count))
+ return false;
+
+ AdvanceCursor(count);
+ return true;
+}
+
+bool NtlmBufferReader::MatchSignature() {
+ if (!CanRead(kSignatureLen))
+ return false;
+
+ if (memcmp(kSignature, GetBufferAtCursor(), kSignatureLen) != 0)
+ return false;
+
+ AdvanceCursor(kSignatureLen);
+ return true;
+}
+
+bool NtlmBufferReader::MatchMessageType(MessageType message_type) {
+ MessageType actual_message_type;
+ return ReadMessageType(&actual_message_type) &&
+ (actual_message_type == message_type);
+}
+
+bool NtlmBufferReader::MatchMessageHeader(MessageType message_type) {
+ return MatchSignature() && MatchMessageType(message_type);
+}
+
+bool NtlmBufferReader::MatchZeros(size_t count) {
+ if (!CanRead(count))
+ return false;
+
+ for (size_t i = 0; i < count; i++) {
+ if (GetBufferAtCursor()[i] != 0)
+ return false;
+ }
+
+ AdvanceCursor(count);
+ return true;
+}
+
+bool NtlmBufferReader::MatchEmptySecurityBuffer() {
+ SecurityBuffer sec_buf;
+ return ReadSecurityBuffer(&sec_buf) && (sec_buf.offset <= GetLength()) &&
+ (sec_buf.length == 0);
+}
+
+template <typename T>
+bool NtlmBufferReader::ReadUInt(T* value) {
+ size_t int_size = sizeof(T);
+ if (!CanRead(int_size))
+ return false;
+
+ *value = 0;
+ for (size_t i = 0; i < int_size; i++) {
+ *value += static_cast<T>(GetByteAtCursor()) << (i * 8);
+ AdvanceCursor(1);
+ }
+
+ return true;
+}
+
+void NtlmBufferReader::SetCursor(size_t cursor) {
+ DCHECK_LE(cursor, GetLength());
+
+ cursor_ = cursor;
+}
+
+} // namespace ntlm
+} // namespace net
diff --git a/chromium/net/ntlm/ntlm_buffer_reader.h b/chromium/net/ntlm/ntlm_buffer_reader.h
new file mode 100644
index 00000000000..d31429f4b71
--- /dev/null
+++ b/chromium/net/ntlm/ntlm_buffer_reader.h
@@ -0,0 +1,191 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_NTLM_BUFFER_READER_H_
+#define NET_BASE_NTLM_BUFFER_READER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/ntlm/ntlm_constants.h"
+
+namespace net {
+namespace ntlm {
+
+// Supports various bounds-checked low level buffer operations required by an
+// NTLM implementation.
+//
+// The class supports the sequential read of a provided buffer. All reads
+// perform bounds checking to ensure enough space is remaining in the buffer.
+//
+// Read* methods read from the buffer at the current cursor position and
+// perform any necessary type conversion and provide the data in out params.
+// After a successful read the cursor position is advanced past the read
+// field.
+//
+// Failed Read*s or Match*s leave the cursor in an undefined position and the
+// buffer MUST be discarded with no further operations performed.
+//
+// Read*Payload methods first reads a security buffer (see
+// |ReadSecurityBuffer|), then reads the requested payload from the offset
+// and length stated in the security buffer.
+//
+// If the length and offset in the security buffer would cause a read outside
+// the message buffer the payload will not be read and the function will
+// return false.
+//
+// Based on [MS-NLMP]: NT LAN Manager (NTLM) Authentication Protocol
+// Specification version 28.0 [1]. Additional NTLM reference [2].
+//
+// [1] https://msdn.microsoft.com/en-us/library/cc236621.aspx
+// [2] http://davenport.sourceforge.net/ntlm.html
+class NET_EXPORT_PRIVATE NtlmBufferReader {
+ public:
+ explicit NtlmBufferReader(base::StringPiece buffer);
+
+ // This class does not take ownership of |ptr|, so the caller must ensure
+ // that the buffer outlives the |NtlmBufferReader|.
+ NtlmBufferReader(const uint8_t* ptr, size_t len);
+ ~NtlmBufferReader();
+
+ size_t GetLength() const { return buffer_.length(); }
+ size_t GetCursor() const { return cursor_; }
+ bool IsEndOfBuffer() const { return cursor_ >= GetLength(); }
+
+ // Returns true if there are |len| more bytes between the current cursor
+ // position and the end of the buffer.
+ bool CanRead(size_t len) const;
+
+ // Returns true if there are |len| more bytes between |offset| and the end
+ // of the buffer. The cursor position is not used or modified.
+ bool CanReadFrom(size_t offset, size_t len) const;
+
+ // Returns true if it would be possible to read the payload described by the
+ // security buffer.
+ bool CanReadFrom(SecurityBuffer sec_buf) const {
+ return CanReadFrom(sec_buf.offset, sec_buf.length);
+ }
+
+ // Reads a 16 bit value (little endian) as a uint16_t. If there are not 16
+ // more bits available, it returns false.
+ bool ReadUInt16(uint16_t* value) WARN_UNUSED_RESULT;
+
+ // Reads a 32 bit value (little endian) as a uint32_t. If there are not 32
+ // more bits available, it returns false.
+ bool ReadUInt32(uint32_t* value) WARN_UNUSED_RESULT;
+
+ // Reads a 64 bit value (little endian) as a uint64_t. If there are not 64
+ // more bits available, it returns false.
+ bool ReadUInt64(uint64_t* value) WARN_UNUSED_RESULT;
+
+ // Calls |ReadUInt32| and returns it cast as |NegotiateFlags|. No
+ // validation of the value takes place.
+ bool ReadFlags(NegotiateFlags* flags) WARN_UNUSED_RESULT;
+
+ // Reads |len| bytes and copies them into |buffer|.
+ bool ReadBytes(uint8_t* buffer, size_t len) WARN_UNUSED_RESULT;
+
+ // Reads |sec_buf.length| bytes from offset |sec_buf.offset| and copies them
+ // into |buffer|. If the security buffer specifies a payload outside the
+ // buffer, then the call fails. Unlike the other Read* methods, this does
+ // not move the cursor.
+ bool ReadBytesFrom(const SecurityBuffer& sec_buf,
+ uint8_t* buffer) WARN_UNUSED_RESULT;
+
+ // A security buffer is an 8 byte structure that defines the offset and
+ // length of a payload (string, struct or byte array) that appears after the
+ // fixed part of the message.
+ //
+ // The structure is (little endian fields):
+ // uint16 - |length| Length of payload
+ // uint16 - Allocation (this is always ignored and not returned)
+ // uint32 - |offset| Offset from start of message
+ bool ReadSecurityBuffer(SecurityBuffer* sec_buf) WARN_UNUSED_RESULT;
+
+ // There are 3 message types Negotiate (sent by client), Challenge (sent by
+ // server), and Authenticate (sent by client).
+ //
+ // This reads the message type from the header and will return false if the
+ // value is invalid.
+ bool ReadMessageType(MessageType* message_type) WARN_UNUSED_RESULT;
+
+ // Skips over a security buffer field without reading the fields. This is
+ // the equivalent of advancing the cursor 8 bytes. Returns false if there
+ // are less than 8 bytes left in the buffer.
+ bool SkipSecurityBuffer() WARN_UNUSED_RESULT;
+
+ // Skips over the security buffer without returning the values, but fails if
+ // the values would cause a read outside the buffer if the payload was
+ // actually read.
+ bool SkipSecurityBufferWithValidation() WARN_UNUSED_RESULT;
+
+ // Skips over |count| bytes in the buffer. Returns false if there are not
+ // |count| bytes left in the buffer.
+ bool SkipBytes(size_t count) WARN_UNUSED_RESULT;
+
+ // Reads and returns true if the next 8 bytes matches the signature in an
+ // NTLM message "NTLMSSP\0". The cursor advances if the the signature
+ // is matched.
+ bool MatchSignature() WARN_UNUSED_RESULT;
+
+ // Performs |ReadMessageType| and returns true if the value is
+ // |message_type|. If the read fails or the message type does not match,
+ // the buffer is invalid and MUST be discarded.
+ bool MatchMessageType(MessageType message_type) WARN_UNUSED_RESULT;
+
+ // Performs |MatchSignature| then |MatchMessageType|.
+ bool MatchMessageHeader(MessageType message_type) WARN_UNUSED_RESULT;
+
+ // Performs |ReadBytes(count)| and returns true if the contents is all
+ // zero.
+ bool MatchZeros(size_t count) WARN_UNUSED_RESULT;
+
+ // Reads the security buffer and returns true if the length is 0 and
+ // the offset is within the message. On failure, the buffer is invalid
+ // and MUST be discarded.
+ bool MatchEmptySecurityBuffer() WARN_UNUSED_RESULT;
+
+ private:
+ // Reads |sizeof(T)| bytes of an integer type from a little-endian buffer.
+ template <typename T>
+ bool ReadUInt(T* value);
+
+ // Sets the cursor position. The caller should use |GetLength|, |CanRead|,
+ // or |CanReadFrom| to verify the bounds before calling this method.
+ void SetCursor(size_t cursor);
+
+ // Advances the cursor by |count| bytes. The caller should use |GetLength|,
+ // |CanRead|, or |CanReadFrom| to verify the bounds before calling this
+ // method.
+ void AdvanceCursor(size_t count) { SetCursor(GetCursor() + count); }
+
+ // Returns a constant pointer to the start of the buffer.
+ const uint8_t* GetBufferPtr() const {
+ return reinterpret_cast<const uint8_t*>(buffer_.data());
+ }
+
+ // Returns a pointer to the underlying buffer at the current cursor
+ // position.
+ const uint8_t* GetBufferAtCursor() const { return GetBufferPtr() + cursor_; }
+
+ // Returns the byte at the current cursor position.
+ uint8_t GetByteAtCursor() const {
+ DCHECK(!IsEndOfBuffer());
+ return *(GetBufferAtCursor());
+ }
+
+ const base::StringPiece buffer_;
+ size_t cursor_;
+
+ DISALLOW_COPY_AND_ASSIGN(NtlmBufferReader);
+};
+
+} // namespace ntlm
+} // namespace net
+
+#endif // NET_BASE_NTLM_BUFFER_READER_H_
diff --git a/chromium/net/ntlm/ntlm_buffer_reader_unittest.cc b/chromium/net/ntlm/ntlm_buffer_reader_unittest.cc
new file mode 100644
index 00000000000..592c5d31862
--- /dev/null
+++ b/chromium/net/ntlm/ntlm_buffer_reader_unittest.cc
@@ -0,0 +1,367 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/ntlm/ntlm_buffer_reader.h"
+
+#include "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace ntlm {
+
+TEST(NtlmBufferReaderTest, Initialization) {
+ const uint8_t buf[1] = {0};
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ ASSERT_EQ(arraysize(buf), reader.GetLength());
+ ASSERT_EQ(0u, reader.GetCursor());
+ ASSERT_FALSE(reader.IsEndOfBuffer());
+ ASSERT_TRUE(reader.CanRead(1));
+ ASSERT_FALSE(reader.CanRead(2));
+ ASSERT_TRUE(reader.CanReadFrom(0, 1));
+ ASSERT_TRUE(reader.CanReadFrom(SecurityBuffer(0, 1)));
+ ASSERT_FALSE(reader.CanReadFrom(1, 1));
+ ASSERT_FALSE(reader.CanReadFrom(SecurityBuffer(1, 1)));
+ ASSERT_FALSE(reader.CanReadFrom(0, 2));
+ ASSERT_FALSE(reader.CanReadFrom(SecurityBuffer(0, 2)));
+
+ // With length=0 the offset can be out of bounds.
+ ASSERT_TRUE(reader.CanReadFrom(99, 0));
+ ASSERT_TRUE(reader.CanReadFrom(SecurityBuffer(99, 0)));
+}
+
+TEST(NtlmBufferReaderTest, Read16) {
+ const uint8_t buf[2] = {0x22, 0x11};
+ const uint16_t expected = 0x1122;
+
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ uint16_t actual;
+ ASSERT_TRUE(reader.ReadUInt16(&actual));
+ ASSERT_EQ(expected, actual);
+ ASSERT_TRUE(reader.IsEndOfBuffer());
+ ASSERT_FALSE(reader.ReadUInt16(&actual));
+}
+
+TEST(NtlmBufferReaderTest, Read32) {
+ const uint8_t buf[4] = {0x44, 0x33, 0x22, 0x11};
+ const uint32_t expected = 0x11223344;
+
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ uint32_t actual;
+ ASSERT_TRUE(reader.ReadUInt32(&actual));
+ ASSERT_EQ(expected, actual);
+ ASSERT_TRUE(reader.IsEndOfBuffer());
+ ASSERT_FALSE(reader.ReadUInt32(&actual));
+}
+
+TEST(NtlmBufferReaderTest, Read64) {
+ const uint8_t buf[8] = {0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11};
+ const uint64_t expected = 0x1122334455667788;
+
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ uint64_t actual;
+ ASSERT_TRUE(reader.ReadUInt64(&actual));
+ ASSERT_EQ(expected, actual);
+ ASSERT_TRUE(reader.IsEndOfBuffer());
+ ASSERT_FALSE(reader.ReadUInt64(&actual));
+}
+
+TEST(NtlmBufferReaderTest, ReadBytes) {
+ const uint8_t expected[8] = {0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11};
+ uint8_t actual[8];
+
+ NtlmBufferReader reader(expected, arraysize(expected));
+
+ ASSERT_TRUE(reader.ReadBytes(actual, arraysize(actual)));
+ ASSERT_EQ(0, memcmp(actual, expected, arraysize(actual)));
+ ASSERT_TRUE(reader.IsEndOfBuffer());
+ ASSERT_FALSE(reader.ReadBytes(actual, 1));
+}
+
+TEST(NtlmBufferReaderTest, ReadSecurityBuffer) {
+ const uint8_t buf[8] = {0x22, 0x11, 0xFF, 0xEE, 0x88, 0x77, 0x66, 0x55};
+ const uint16_t length = 0x1122;
+ const uint32_t offset = 0x55667788;
+
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ SecurityBuffer sec_buf;
+ ASSERT_TRUE(reader.ReadSecurityBuffer(&sec_buf));
+ ASSERT_EQ(length, sec_buf.length);
+ ASSERT_EQ(offset, sec_buf.offset);
+ ASSERT_TRUE(reader.IsEndOfBuffer());
+ ASSERT_FALSE(reader.ReadSecurityBuffer(&sec_buf));
+}
+
+TEST(NtlmBufferReaderTest, ReadSecurityBufferPastEob) {
+ const uint8_t buf[7] = {0};
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ SecurityBuffer sec_buf;
+ ASSERT_FALSE(reader.ReadSecurityBuffer(&sec_buf));
+}
+
+TEST(NtlmBufferReaderTest, SkipSecurityBuffer) {
+ const uint8_t buf[kSecurityBufferLen] = {0};
+
+ NtlmBufferReader reader(buf, arraysize(buf));
+ ASSERT_TRUE(reader.SkipSecurityBuffer());
+ ASSERT_TRUE(reader.IsEndOfBuffer());
+ ASSERT_FALSE(reader.SkipSecurityBuffer());
+}
+
+TEST(NtlmBufferReaderTest, SkipSecurityBufferPastEob) {
+ // The buffer is one byte shorter than security buffer.
+ const uint8_t buf[kSecurityBufferLen - 1] = {0};
+
+ NtlmBufferReader reader(buf, arraysize(buf));
+ ASSERT_FALSE(reader.SkipSecurityBuffer());
+}
+
+TEST(NtlmBufferReaderTest, SkipSecurityBufferWithValidationEmpty) {
+ const uint8_t buf[kSecurityBufferLen] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+ NtlmBufferReader reader(buf, arraysize(buf));
+ ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
+ ASSERT_TRUE(reader.IsEndOfBuffer());
+ ASSERT_FALSE(reader.SkipSecurityBufferWithValidation());
+}
+
+TEST(NtlmBufferReaderTest, SkipSecurityBufferWithValidationValid) {
+ // A valid security buffer that points to the 1 payload byte.
+ const uint8_t buf[kSecurityBufferLen + 1] = {
+ 0x01, 0, 0x01, 0, kSecurityBufferLen, 0, 0, 0, 0xFF};
+
+ NtlmBufferReader reader(buf, arraysize(buf));
+ ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
+ ASSERT_EQ(kSecurityBufferLen, reader.GetCursor());
+ ASSERT_FALSE(reader.SkipSecurityBufferWithValidation());
+}
+
+TEST(NtlmBufferReaderTest,
+ SkipSecurityBufferWithValidationPayloadLengthPastEob) {
+ // Security buffer with length that points past the end of buffer.
+ const uint8_t buf[kSecurityBufferLen + 1] = {
+ 0x02, 0, 0x02, 0, kSecurityBufferLen, 0, 0, 0, 0xFF};
+
+ NtlmBufferReader reader(buf, arraysize(buf));
+ ASSERT_FALSE(reader.SkipSecurityBufferWithValidation());
+}
+
+TEST(NtlmBufferReaderTest,
+ SkipSecurityBufferWithValidationPayloadOffsetPastEob) {
+ // Security buffer with offset that points past the end of buffer.
+ const uint8_t buf[kSecurityBufferLen + 1] = {
+ 0x02, 0, 0x02, 0, kSecurityBufferLen + 1, 0, 0, 0, 0xFF};
+
+ NtlmBufferReader reader(buf, arraysize(buf));
+ ASSERT_FALSE(reader.SkipSecurityBufferWithValidation());
+}
+
+TEST(NtlmBufferReaderTest,
+ SkipSecurityBufferWithValidationZeroLengthPayloadOffsetPastEob) {
+ // Security buffer with offset that points past the end of buffer but
+ // length is 0.
+ const uint8_t buf[kSecurityBufferLen] = {0, 0, 0, 0, kSecurityBufferLen + 1,
+ 0, 0, 0};
+
+ NtlmBufferReader reader(buf, arraysize(buf));
+ ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
+ ASSERT_EQ(kSecurityBufferLen, reader.GetCursor());
+}
+
+TEST(NtlmBufferReaderTest, SkipBytes) {
+ const uint8_t buf[8] = {0};
+
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ ASSERT_TRUE(reader.SkipBytes(arraysize(buf)));
+ ASSERT_TRUE(reader.IsEndOfBuffer());
+ ASSERT_FALSE(reader.SkipBytes(arraysize(buf)));
+}
+
+TEST(NtlmBufferReaderTest, SkipBytesPastEob) {
+ const uint8_t buf[8] = {0};
+
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ ASSERT_FALSE(reader.SkipBytes(arraysize(buf) + 1));
+}
+
+TEST(NtlmBufferReaderTest, MatchSignatureTooShort) {
+ const uint8_t buf[7] = {0};
+
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ ASSERT_TRUE(reader.CanRead(7));
+ ASSERT_FALSE(reader.MatchSignature());
+}
+
+TEST(NtlmBufferReaderTest, MatchSignatureNoMatch) {
+ // The last byte should be a 0.
+ const uint8_t buf[8] = {'N', 'T', 'L', 'M', 'S', 'S', 'P', 0xff};
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ ASSERT_TRUE(reader.CanRead(8));
+ ASSERT_FALSE(reader.MatchSignature());
+}
+
+TEST(NtlmBufferReaderTest, MatchSignatureOk) {
+ const uint8_t buf[8] = {'N', 'T', 'L', 'M', 'S', 'S', 'P', 0};
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ ASSERT_TRUE(reader.MatchSignature());
+ ASSERT_TRUE(reader.IsEndOfBuffer());
+}
+
+TEST(NtlmBufferReaderTest, ReadInvalidMessageType) {
+ // Only 0x01, 0x02, and 0x03 are valid message types.
+ const uint8_t buf[4] = {0x04, 0, 0, 0};
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ MessageType message_type;
+ ASSERT_FALSE(reader.ReadMessageType(&message_type));
+}
+
+TEST(NtlmBufferReaderTest, ReadMessageTypeNegotiate) {
+ const uint8_t buf[4] = {static_cast<uint8_t>(MessageType::kNegotiate), 0, 0,
+ 0};
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ MessageType message_type;
+ ASSERT_TRUE(reader.ReadMessageType(&message_type));
+ ASSERT_EQ(MessageType::kNegotiate, message_type);
+ ASSERT_TRUE(reader.IsEndOfBuffer());
+}
+
+TEST(NtlmBufferReaderTest, ReadMessageTypeChallenge) {
+ const uint8_t buf[4] = {static_cast<uint8_t>(MessageType::kChallenge), 0, 0,
+ 0};
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ MessageType message_type;
+ ASSERT_TRUE(reader.ReadMessageType(&message_type));
+ ASSERT_EQ(MessageType::kChallenge, message_type);
+ ASSERT_TRUE(reader.IsEndOfBuffer());
+}
+
+TEST(NtlmBufferReaderTest, ReadMessageTypeAuthenticate) {
+ const uint8_t buf[4] = {static_cast<uint8_t>(MessageType::kAuthenticate), 0,
+ 0, 0};
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ MessageType message_type;
+ ASSERT_TRUE(reader.ReadMessageType(&message_type));
+ ASSERT_EQ(MessageType::kAuthenticate, message_type);
+ ASSERT_TRUE(reader.IsEndOfBuffer());
+}
+
+TEST(NtlmBufferReaderTest, MatchMessageTypeAuthenticate) {
+ const uint8_t buf[4] = {static_cast<uint8_t>(MessageType::kAuthenticate), 0,
+ 0, 0};
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ ASSERT_TRUE(reader.MatchMessageType(MessageType::kAuthenticate));
+ ASSERT_TRUE(reader.IsEndOfBuffer());
+}
+
+TEST(NtlmBufferReaderTest, MatchMessageTypeInvalid) {
+ // Only 0x01, 0x02, and 0x03 are valid message types.
+ const uint8_t buf[4] = {0x04, 0, 0, 0};
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ ASSERT_FALSE(reader.MatchMessageType(MessageType::kAuthenticate));
+}
+
+TEST(NtlmBufferReaderTest, MatchMessageTypeMismatch) {
+ const uint8_t buf[4] = {static_cast<uint8_t>(MessageType::kChallenge), 0, 0,
+ 0};
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ ASSERT_FALSE(reader.MatchMessageType(MessageType::kAuthenticate));
+}
+
+TEST(NtlmBufferReaderTest, MatchAuthenticateHeader) {
+ const uint8_t buf[12] = {
+ 'N', 'T', 'L',
+ 'M', 'S', 'S',
+ 'P', 0, static_cast<uint8_t>(MessageType::kAuthenticate),
+ 0, 0, 0};
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ ASSERT_TRUE(reader.MatchMessageHeader(MessageType::kAuthenticate));
+ ASSERT_TRUE(reader.IsEndOfBuffer());
+}
+
+TEST(NtlmBufferReaderTest, MatchAuthenticateHeaderMisMatch) {
+ const uint8_t buf[12] = {
+ 'N', 'T', 'L',
+ 'M', 'S', 'S',
+ 'P', 0, static_cast<uint8_t>(MessageType::kChallenge),
+ 0, 0, 0};
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ ASSERT_FALSE(reader.MatchMessageType(MessageType::kAuthenticate));
+}
+
+TEST(NtlmBufferReaderTest, MatchZeros) {
+ const uint8_t buf[6] = {0, 0, 0, 0, 0, 0};
+
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ ASSERT_TRUE(reader.MatchZeros(arraysize(buf)));
+ ASSERT_TRUE(reader.IsEndOfBuffer());
+ ASSERT_FALSE(reader.MatchZeros(1));
+}
+
+TEST(NtlmBufferReaderTest, MatchZerosFail) {
+ const uint8_t buf[6] = {0, 0, 0, 0, 0, 0xFF};
+
+ NtlmBufferReader reader(buf, arraysize(buf));
+
+ ASSERT_FALSE(reader.MatchZeros(arraysize(buf)));
+}
+
+TEST(NtlmBufferReaderTest, MatchEmptySecurityBuffer) {
+ const uint8_t buf[kSecurityBufferLen] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+ NtlmBufferReader reader(buf, kSecurityBufferLen);
+
+ ASSERT_TRUE(reader.MatchEmptySecurityBuffer());
+ ASSERT_TRUE(reader.IsEndOfBuffer());
+ ASSERT_FALSE(reader.MatchEmptySecurityBuffer());
+}
+
+TEST(NtlmBufferReaderTest, MatchEmptySecurityBufferLengthZeroOffsetEnd) {
+ const uint8_t buf[kSecurityBufferLen] = {0, 0, 0, 0, 0x08, 0, 0, 0};
+
+ NtlmBufferReader reader(buf, kSecurityBufferLen);
+
+ ASSERT_TRUE(reader.MatchEmptySecurityBuffer());
+ ASSERT_TRUE(reader.IsEndOfBuffer());
+}
+
+TEST(NtlmBufferReaderTest, MatchEmptySecurityBufferLengthZeroPastEob) {
+ const uint8_t buf[kSecurityBufferLen] = {0, 0, 0, 0, 0x09, 0, 0, 0};
+
+ NtlmBufferReader reader(buf, kSecurityBufferLen);
+
+ ASSERT_FALSE(reader.MatchEmptySecurityBuffer());
+}
+
+TEST(NtlmBufferReaderTest, MatchEmptySecurityBufferLengthNonZeroLength) {
+ const uint8_t buf[kSecurityBufferLen + 1] = {0x01, 0, 0, 0, 0x08,
+ 0, 0, 0, 0xff};
+
+ NtlmBufferReader reader(buf, kSecurityBufferLen);
+
+ ASSERT_FALSE(reader.MatchEmptySecurityBuffer());
+}
+
+} // namespace ntlm
+} // namespace net
diff --git a/chromium/net/ntlm/ntlm_buffer_writer.cc b/chromium/net/ntlm/ntlm_buffer_writer.cc
new file mode 100644
index 00000000000..0b5e3aa5c81
--- /dev/null
+++ b/chromium/net/ntlm/ntlm_buffer_writer.cc
@@ -0,0 +1,152 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/ntlm/ntlm_buffer_writer.h"
+
+#include <string.h>
+
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+
+namespace net {
+namespace ntlm {
+
+NtlmBufferWriter::NtlmBufferWriter(size_t buffer_len)
+ : buffer_len_(buffer_len), cursor_(0) {
+ buffer_.reset(new uint8_t[buffer_len]());
+}
+
+NtlmBufferWriter::~NtlmBufferWriter() {}
+
+bool NtlmBufferWriter::CanWrite(size_t len) const {
+ if (!GetBufferPtr())
+ return false;
+
+ DCHECK_LE(GetCursor(), GetLength());
+
+ if (len == 0)
+ return true;
+
+ return (len <= GetLength()) && (GetCursor() <= GetLength() - len);
+}
+
+bool NtlmBufferWriter::WriteUInt16(uint16_t value) {
+ return WriteUInt<uint16_t>(value);
+}
+
+bool NtlmBufferWriter::WriteUInt32(uint32_t value) {
+ return WriteUInt<uint32_t>(value);
+}
+
+bool NtlmBufferWriter::WriteUInt64(uint64_t value) {
+ return WriteUInt<uint64_t>(value);
+}
+
+bool NtlmBufferWriter::WriteFlags(NegotiateFlags flags) {
+ return WriteUInt32(static_cast<uint32_t>(flags));
+}
+
+bool NtlmBufferWriter::WriteBytes(const uint8_t* buffer, size_t len) {
+ if (!CanWrite(len))
+ return false;
+
+ memcpy(reinterpret_cast<void*>(GetBufferPtrAtCursor()),
+ reinterpret_cast<const void*>(buffer), len);
+
+ AdvanceCursor(len);
+ return true;
+}
+
+bool NtlmBufferWriter::WriteBytes(base::StringPiece bytes) {
+ return WriteBytes(reinterpret_cast<const uint8_t*>(bytes.data()),
+ bytes.length());
+}
+
+bool NtlmBufferWriter::WriteZeros(size_t count) {
+ if (!CanWrite(count))
+ return false;
+
+ memset(GetBufferPtrAtCursor(), 0, count);
+ AdvanceCursor(count);
+ return true;
+}
+
+bool NtlmBufferWriter::WriteSecurityBuffer(SecurityBuffer sec_buf) {
+ return WriteUInt16(sec_buf.length) && WriteUInt16(sec_buf.length) &&
+ WriteUInt32(sec_buf.offset);
+}
+
+bool NtlmBufferWriter::WriteUtf8String(const std::string& str) {
+ return WriteBytes(reinterpret_cast<const uint8_t*>(str.c_str()),
+ str.length());
+}
+
+bool NtlmBufferWriter::WriteUtf16AsUtf8String(const base::string16& str) {
+ std::string utf8 = base::UTF16ToUTF8(str);
+ return WriteUtf8String(utf8);
+}
+
+bool NtlmBufferWriter::WriteUtf8AsUtf16String(const std::string& str) {
+ base::string16 unicode = base::UTF8ToUTF16(str);
+ return WriteUtf16String(unicode);
+}
+
+bool NtlmBufferWriter::WriteUtf16String(const base::string16& str) {
+ size_t num_bytes = str.length() * 2;
+ if (!CanWrite(num_bytes))
+ return false;
+
+#if defined(ARCH_CPU_BIG_ENDIAN)
+ uint8_t* ptr = reinterpret_cast<uint8_t*>(GetBufferPtrAtCursor());
+
+ for (int i = 0; i < num_bytes; i += 2) {
+ ptr[i] = str[i / 2] & 0xff;
+ ptr[i + 1] = str[i / 2] >> 8;
+ }
+#else
+ memcpy(reinterpret_cast<void*>(GetBufferPtrAtCursor()), str.c_str(),
+ num_bytes);
+
+#endif
+
+ AdvanceCursor(num_bytes);
+ return true;
+}
+
+bool NtlmBufferWriter::WriteSignature() {
+ return WriteBytes(kSignature, kSignatureLen);
+}
+
+bool NtlmBufferWriter::WriteMessageType(MessageType message_type) {
+ return WriteUInt32(static_cast<uint32_t>(message_type));
+}
+
+bool NtlmBufferWriter::WriteMessageHeader(MessageType message_type) {
+ return WriteSignature() && WriteMessageType(message_type);
+}
+
+template <typename T>
+bool NtlmBufferWriter::WriteUInt(T value) {
+ size_t int_size = sizeof(T);
+ if (!CanWrite(int_size))
+ return false;
+
+ for (size_t i = 0; i < int_size; i++) {
+ GetBufferPtrAtCursor()[i] = static_cast<uint8_t>(value & 0xff);
+ value >>= 8;
+ }
+
+ AdvanceCursor(int_size);
+ return true;
+}
+
+void NtlmBufferWriter::SetCursor(size_t cursor) {
+ DCHECK(GetBufferPtr() && cursor <= GetLength());
+
+ cursor_ = cursor;
+}
+
+} // namespace ntlm
+} // namespace net
diff --git a/chromium/net/ntlm/ntlm_buffer_writer.h b/chromium/net/ntlm/ntlm_buffer_writer.h
new file mode 100644
index 00000000000..067885dda05
--- /dev/null
+++ b/chromium/net/ntlm/ntlm_buffer_writer.h
@@ -0,0 +1,177 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_NTLM_BUFFER_WRITER_H_
+#define NET_BASE_NTLM_BUFFER_WRITER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/ntlm/ntlm_constants.h"
+
+namespace net {
+namespace ntlm {
+
+// Supports various bounds checked low level buffer operations required by an
+// NTLM implementation.
+//
+// The class supports sequential write to an internally managed buffer. All
+// writes perform bounds checking to ensure enough space is remaining in the
+// buffer.
+//
+// The internal buffer is allocated in the constructor with size |buffer_len|
+// and owned by the class.
+//
+// Write* methods write the buffer at the current cursor position and perform
+// any necessary type conversion and provide the data in out params. After a
+// successful write the cursor position is advanced past the written field.
+//
+// Failed writes leave the internal cursor at the same position as before the
+// call.
+//
+// Based on [MS-NLMP]: NT LAN Manager (NTLM) Authentication Protocol
+// Specification version 28.0 [1]. Additional NTLM reference [2].
+//
+// [1] https://msdn.microsoft.com/en-us/library/cc236621.aspx
+// [2] http://davenport.sourceforge.net/ntlm.html
+class NET_EXPORT_PRIVATE NtlmBufferWriter {
+ public:
+ explicit NtlmBufferWriter(size_t buffer_len);
+ ~NtlmBufferWriter();
+
+ size_t GetLength() const { return buffer_len_; }
+ size_t GetCursor() const { return cursor_; }
+ bool IsEndOfBuffer() const { return cursor_ >= GetLength(); }
+
+ // Gets a base::StringPiece view over the entire buffer.
+ base::StringPiece GetBuffer() const {
+ return base::StringPiece(reinterpret_cast<const char*>(buffer_.get()),
+ buffer_len_);
+ }
+
+ // Returns true if there are |len| more bytes between the current cursor
+ // position and the end of the buffer.
+ bool CanWrite(size_t len) const;
+
+ // Writes a 16 bit unsigned value (little endian). If there are not 16
+ // more bits available in the buffer, it returns false.
+ bool WriteUInt16(uint16_t value) WARN_UNUSED_RESULT;
+
+ // Writes a 32 bit unsigned value (little endian). If there are not 32
+ // more bits available in the buffer, it returns false.
+ bool WriteUInt32(uint32_t value) WARN_UNUSED_RESULT;
+
+ // Writes a 64 bit unsigned value (little endian). If there are not 64
+ // more bits available in the buffer, it returns false.
+ bool WriteUInt64(uint64_t value) WARN_UNUSED_RESULT;
+
+ // Writes flags as a 32 bit unsigned value (little endian).
+ bool WriteFlags(NegotiateFlags flags) WARN_UNUSED_RESULT;
+
+ // Writes |len| bytes from |buffer|. If there are not |len| more bytes in
+ // the buffer, it returns false.
+ bool WriteBytes(const uint8_t* buffer, size_t len) WARN_UNUSED_RESULT;
+
+ // Writes the bytes from the |base::StringPiece|. If there are not enough
+ // bytes in the buffer, it returns false.
+ bool WriteBytes(base::StringPiece bytes) WARN_UNUSED_RESULT;
+
+ // Writes |count| bytes of zeros to the buffer. If there are not |count|
+ // more bytes in available in the buffer, it returns false.
+ bool WriteZeros(size_t count) WARN_UNUSED_RESULT;
+
+ // A security buffer is an 8 byte structure that defines the offset and
+ // length of a payload (string, struct, or byte array) that appears after
+ // the fixed part of the message.
+ //
+ // The structure in the NTLM message is (little endian fields):
+ // uint16 - |length| Length of payload
+ // uint16 - Allocation (ignored and always set to |length|)
+ // uint32 - |offset| Offset from start of message
+ bool WriteSecurityBuffer(SecurityBuffer sec_buf) WARN_UNUSED_RESULT;
+
+ // Writes a string of 8 bit characters to the buffer.
+ //
+ // When Unicode was not negotiated only the hostname string will go through
+ // this code path. The 8 bit bytes of the hostname are written to the buffer.
+ // The encoding is not relevant.
+ bool WriteUtf8String(const std::string& str) WARN_UNUSED_RESULT;
+
+ // Converts the 16 bit characters to UTF8 and writes the resulting 8 bit
+ // characters.
+ //
+ // If Unicode was not negotiated, the username and domain get converted to
+ // UTF8 in the message. Since they are just treated as additional bytes
+ // input to hash the encoding doesn't matter. In practice, only a very old or
+ // non-Windows server might trigger this code path since we always attempt
+ // to negotiate Unicode and servers are supposed to honor that request.
+ bool WriteUtf16AsUtf8String(const base::string16& str) WARN_UNUSED_RESULT;
+
+ // Treats |str| as UTF8, converts to UTF-16 and writes it with little-endian
+ // byte order to the buffer.
+ //
+ // Two specific strings go through this code path.
+ //
+ // One case is the hostname. When the the Unicode flag has been set during
+ // negotiation, the hostname needs to appear in the message with 16-bit
+ // characters.
+ //
+ // The other case is the Service Principal Name (SPN). With Extended
+ // Protection for Authentication (EPA) enabled, it appears in the target info
+ // inside an AV Pair, where strings always have 16-bit characters.
+ bool WriteUtf8AsUtf16String(const std::string& str) WARN_UNUSED_RESULT;
+
+ // Writes UTF-16 LE characters to the buffer. For these strings, such as
+ // username and the domain the actual encoding isn't important; they are just
+ // treated as additional bytes of input to the hash.
+ bool WriteUtf16String(const base::string16& str) WARN_UNUSED_RESULT;
+
+ // Writes the 8 byte NTLM signature "NTLMSSP\0" into the buffer.
+ bool WriteSignature() WARN_UNUSED_RESULT;
+
+ // There are 3 message types Negotiate (sent by client), Challenge (sent by
+ // server), and Authenticate (sent by client).
+ //
+ // This writes |message_type| as a uint32_t into the buffer.
+ bool WriteMessageType(MessageType message_type) WARN_UNUSED_RESULT;
+
+ // Performs |WriteSignature| then |WriteMessageType|.
+ bool WriteMessageHeader(MessageType message_type) WARN_UNUSED_RESULT;
+
+ private:
+ // Writes |sizeof(T)| bytes little-endian of an integer type to the buffer.
+ template <typename T>
+ bool WriteUInt(T value);
+
+ // Sets the cursor position. The caller should use |GetLength| or
+ // |CanWrite| to verify the bounds before calling this method.
+ void SetCursor(size_t cursor);
+
+ // Advances the cursor by |count|. The caller should use |GetLength| or
+ // |CanWrite| to verify the bounds before calling this method.
+ void AdvanceCursor(size_t count) { SetCursor(GetCursor() + count); }
+
+ // Returns a pointer to the start of the buffer.
+ uint8_t* GetBufferPtr() const { return buffer_.get(); }
+
+ // Returns pointer into the buffer at the current cursor location.
+ uint8_t* GetBufferPtrAtCursor() const { return buffer_.get() + GetCursor(); }
+
+ std::unique_ptr<uint8_t[]> buffer_;
+ size_t buffer_len_;
+ size_t cursor_;
+
+ DISALLOW_COPY_AND_ASSIGN(NtlmBufferWriter);
+};
+
+} // namespace ntlm
+} // namespace net
+
+#endif // NET_BASE_NTLM_BUFFER_WRITER_H_
diff --git a/chromium/net/ntlm/ntlm_buffer_writer_unittest.cc b/chromium/net/ntlm/ntlm_buffer_writer_unittest.cc
new file mode 100644
index 00000000000..3616b9fc180
--- /dev/null
+++ b/chromium/net/ntlm/ntlm_buffer_writer_unittest.cc
@@ -0,0 +1,235 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/ntlm/ntlm_buffer_writer.h"
+
+#include "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace ntlm {
+
+namespace {
+
+// Helper method to hide all the ugly casting.
+const uint8_t* GetBufferPtr(const NtlmBufferWriter& writer) {
+ return reinterpret_cast<const uint8_t*>(writer.GetBuffer().data());
+}
+
+// Helper method to get a byte at a specific index in the buffer.
+uint8_t GetByteFromBuffer(const NtlmBufferWriter& writer, size_t index) {
+ base::StringPiece piece(writer.GetBuffer());
+ EXPECT_TRUE(index < piece.length());
+ return static_cast<uint8_t>(piece.data()[index]);
+}
+
+} // namespace
+
+TEST(NtlmBufferWriterTest, Initialization) {
+ NtlmBufferWriter writer(1);
+
+ ASSERT_EQ(1u, writer.GetLength());
+ ASSERT_EQ(1u, writer.GetBuffer().length());
+ ASSERT_EQ(0u, writer.GetCursor());
+ ASSERT_FALSE(writer.IsEndOfBuffer());
+ ASSERT_TRUE(writer.CanWrite(1));
+ ASSERT_FALSE(writer.CanWrite(2));
+}
+
+TEST(NtlmBufferWriterTest, Write16) {
+ uint8_t expected[2] = {0x22, 0x11};
+ const uint16_t value = 0x1122;
+
+ NtlmBufferWriter writer(sizeof(uint16_t));
+
+ ASSERT_TRUE(writer.WriteUInt16(value));
+ ASSERT_TRUE(writer.IsEndOfBuffer());
+ ASSERT_EQ(arraysize(expected), writer.GetLength());
+ ASSERT_FALSE(writer.WriteUInt16(value));
+
+ ASSERT_EQ(0,
+ memcmp(expected, writer.GetBuffer().data(), arraysize(expected)));
+}
+
+TEST(NtlmBufferWriterTest, Write16PastEob) {
+ NtlmBufferWriter writer(sizeof(uint16_t) - 1);
+
+ ASSERT_FALSE(writer.WriteUInt16(0));
+ ASSERT_EQ(0u, writer.GetCursor());
+}
+
+TEST(NtlmBufferWriterTest, Write32) {
+ uint8_t expected[4] = {0x44, 0x33, 0x22, 0x11};
+ const uint32_t value = 0x11223344;
+
+ NtlmBufferWriter writer(sizeof(uint32_t));
+
+ ASSERT_TRUE(writer.WriteUInt32(value));
+ ASSERT_TRUE(writer.IsEndOfBuffer());
+ ASSERT_FALSE(writer.WriteUInt32(value));
+
+ ASSERT_EQ(0, memcmp(expected, GetBufferPtr(writer), arraysize(expected)));
+}
+
+TEST(NtlmBufferWriterTest, Write32PastEob) {
+ NtlmBufferWriter writer(sizeof(uint32_t) - 1);
+
+ ASSERT_FALSE(writer.WriteUInt32(0));
+ ASSERT_EQ(0u, writer.GetCursor());
+}
+
+TEST(NtlmBufferWriterTest, Write64) {
+ uint8_t expected[8] = {0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11};
+ const uint64_t value = 0x1122334455667788;
+
+ NtlmBufferWriter writer(sizeof(uint64_t));
+
+ ASSERT_TRUE(writer.WriteUInt64(value));
+ ASSERT_TRUE(writer.IsEndOfBuffer());
+ ASSERT_FALSE(writer.WriteUInt64(value));
+
+ ASSERT_EQ(0, memcmp(expected, GetBufferPtr(writer), arraysize(expected)));
+}
+
+TEST(NtlmBufferWriterTest, Write64PastEob) {
+ NtlmBufferWriter writer(sizeof(uint64_t) - 1);
+
+ ASSERT_FALSE(writer.WriteUInt64(0));
+ ASSERT_EQ(0u, writer.GetCursor());
+}
+
+TEST(NtlmBufferWriterTest, WriteBytes) {
+ uint8_t expected[8] = {0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11};
+
+ NtlmBufferWriter writer(arraysize(expected));
+
+ ASSERT_TRUE(writer.WriteBytes(expected, arraysize(expected)));
+ ASSERT_EQ(0, memcmp(GetBufferPtr(writer), expected, arraysize(expected)));
+ ASSERT_TRUE(writer.IsEndOfBuffer());
+ ASSERT_FALSE(writer.WriteBytes(expected, 1));
+
+ ASSERT_EQ(0, memcmp(expected, GetBufferPtr(writer), arraysize(expected)));
+}
+
+TEST(NtlmBufferWriterTest, WriteBytesPastEob) {
+ uint8_t buffer[8];
+
+ NtlmBufferWriter writer(arraysize(buffer) - 1);
+
+ ASSERT_FALSE(writer.WriteBytes(buffer, arraysize(buffer)));
+}
+
+TEST(NtlmBufferWriterTest, WriteSecurityBuffer) {
+ uint8_t expected[8] = {0x22, 0x11, 0x22, 0x11, 0x88, 0x77, 0x66, 0x55};
+ uint16_t length = 0x1122;
+ uint32_t offset = 0x55667788;
+
+ NtlmBufferWriter writer(kSecurityBufferLen);
+
+ ASSERT_TRUE(writer.WriteSecurityBuffer(SecurityBuffer(offset, length)));
+ ASSERT_TRUE(writer.IsEndOfBuffer());
+ ASSERT_FALSE(writer.WriteSecurityBuffer(SecurityBuffer(offset, length)));
+
+ ASSERT_EQ(0, memcmp(expected, GetBufferPtr(writer), arraysize(expected)));
+}
+
+TEST(NtlmBufferWriterTest, WriteSecurityBufferPastEob) {
+ SecurityBuffer sec_buf;
+ NtlmBufferWriter writer(kSecurityBufferLen - 1);
+
+ ASSERT_FALSE(writer.WriteSecurityBuffer(sec_buf));
+}
+
+TEST(NtlmBufferWriterTest, WriteNarrowString) {
+ uint8_t expected[8] = {'1', '2', '3', '4', '5', '6', '7', '8'};
+ std::string value("12345678");
+
+ NtlmBufferWriter writer(value.size());
+
+ ASSERT_TRUE(writer.WriteUtf8String(value));
+ ASSERT_TRUE(writer.IsEndOfBuffer());
+ ASSERT_FALSE(writer.WriteUtf8String(value));
+
+ ASSERT_EQ(0, memcmp(expected, GetBufferPtr(writer), arraysize(expected)));
+}
+
+TEST(NtlmBufferWriterTest, WriteAsciiStringPastEob) {
+ std::string str("12345678");
+ NtlmBufferWriter writer(str.length() - 1);
+
+ ASSERT_FALSE(writer.WriteUtf8String(str));
+}
+
+TEST(NtlmBufferWriterTest, WriteUtf16String) {
+ uint8_t expected[16] = {'1', 0, '2', 0, '3', 0, '4', 0,
+ '5', 0, '6', 0, '7', 0, '8', 0};
+ base::string16 value = base::ASCIIToUTF16("12345678");
+
+ NtlmBufferWriter writer(value.size() * 2);
+
+ ASSERT_TRUE(writer.WriteUtf16String(value));
+ ASSERT_TRUE(writer.IsEndOfBuffer());
+ ASSERT_FALSE(writer.WriteUtf16String(value));
+
+ ASSERT_EQ(0, memcmp(expected, GetBufferPtr(writer), arraysize(expected)));
+}
+
+TEST(NtlmBufferWriterTest, WriteUtf16StringPastEob) {
+ base::string16 str = base::ASCIIToUTF16("12345678");
+ NtlmBufferWriter writer((str.length() * 2) - 1);
+
+ ASSERT_FALSE(writer.WriteUtf16String(str));
+}
+
+TEST(NtlmBufferWriterTest, WriteUtf8AsUtf16String) {
+ uint8_t expected[16] = {'1', 0, '2', 0, '3', 0, '4', 0,
+ '5', 0, '6', 0, '7', 0, '8', 0};
+ std::string input = "12345678";
+
+ NtlmBufferWriter writer(input.size() * 2);
+
+ ASSERT_TRUE(writer.WriteUtf8AsUtf16String(input));
+ ASSERT_TRUE(writer.IsEndOfBuffer());
+ ASSERT_FALSE(writer.WriteUtf8AsUtf16String(input));
+
+ ASSERT_EQ(0, memcmp(expected, GetBufferPtr(writer), arraysize(expected)));
+}
+
+TEST(NtlmBufferWriterTest, WriteSignature) {
+ uint8_t expected[8] = {'N', 'T', 'L', 'M', 'S', 'S', 'P', 0};
+ NtlmBufferWriter writer(kSignatureLen);
+
+ ASSERT_TRUE(writer.WriteSignature());
+ ASSERT_TRUE(writer.IsEndOfBuffer());
+
+ ASSERT_EQ(0, memcmp(expected, GetBufferPtr(writer), arraysize(expected)));
+}
+
+TEST(NtlmBufferWriterTest, WriteSignaturePastEob) {
+ NtlmBufferWriter writer(1);
+
+ ASSERT_FALSE(writer.WriteSignature());
+}
+
+TEST(NtlmBufferWriterTest, WriteMessageType) {
+ NtlmBufferWriter writer(4);
+
+ ASSERT_TRUE(writer.WriteMessageType(MessageType::kNegotiate));
+ ASSERT_TRUE(writer.IsEndOfBuffer());
+ ASSERT_EQ(static_cast<uint32_t>(MessageType::kNegotiate),
+ GetByteFromBuffer(writer, 0));
+ ASSERT_EQ(0, GetByteFromBuffer(writer, 1));
+ ASSERT_EQ(0, GetByteFromBuffer(writer, 2));
+ ASSERT_EQ(0, GetByteFromBuffer(writer, 3));
+}
+
+TEST(NtlmBufferWriterTest, WriteMessageTypePastEob) {
+ NtlmBufferWriter writer(sizeof(uint32_t) - 1);
+
+ ASSERT_FALSE(writer.WriteMessageType(MessageType::kNegotiate));
+}
+
+} // namespace ntlm
+} // namespace net
diff --git a/chromium/net/ntlm/ntlm_constants.h b/chromium/net/ntlm/ntlm_constants.h
new file mode 100644
index 00000000000..8dc6bb3cde8
--- /dev/null
+++ b/chromium/net/ntlm/ntlm_constants.h
@@ -0,0 +1,91 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_NTLM_CONSTANTS_H_
+#define NET_BASE_NTLM_CONSTANTS_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <type_traits>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+
+namespace net {
+namespace ntlm {
+
+// A security buffer is a structure within an NTLM message that indicates
+// the offset from the beginning of the message and the length of a payload
+// that occurs later in the message. Within the raw message there is also
+// an additional field, however the field is always written with the same
+// value as length, and readers must always ignore it.
+struct SecurityBuffer {
+ SecurityBuffer(uint32_t offset, uint16_t length)
+ : offset(offset), length(length) {}
+ SecurityBuffer() : SecurityBuffer(0, 0) {}
+
+ uint32_t offset;
+ uint16_t length;
+};
+
+enum class NtlmVersion {
+ kNtlmV1 = 0x01,
+ kNtlmV2 = 0x02,
+};
+
+// There are 3 types of messages in NTLM. The message type is a field in
+// every NTLM message header.
+enum class MessageType : uint32_t {
+ kNegotiate = 0x01,
+ kChallenge = 0x02,
+ kAuthenticate = 0x03,
+};
+
+// Defined in [MS-NLMP] Section 2.2.2.5
+// Only the used subset is defined.
+enum class NegotiateFlags : uint32_t {
+ kNone = 0,
+ kUnicode = 0x01,
+ kOem = 0x02,
+ kRequestTarget = 0x04,
+ kNtlm = 0x200,
+ kAlwaysSign = 0x8000,
+ kExtendedSessionSecurity = 0x80000,
+};
+
+constexpr inline NegotiateFlags operator|(NegotiateFlags lhs,
+ NegotiateFlags rhs) {
+ using TFlagsInt = std::underlying_type<NegotiateFlags>::type;
+
+ return static_cast<NegotiateFlags>(static_cast<TFlagsInt>(lhs) |
+ static_cast<TFlagsInt>(rhs));
+}
+
+constexpr inline NegotiateFlags operator&(NegotiateFlags lhs,
+ NegotiateFlags rhs) {
+ using TFlagsInt = std::underlying_type<NegotiateFlags>::type;
+
+ return static_cast<NegotiateFlags>(static_cast<TFlagsInt>(lhs) &
+ static_cast<TFlagsInt>(rhs));
+}
+
+static constexpr uint8_t kSignature[] = "NTLMSSP";
+static constexpr size_t kSignatureLen = arraysize(kSignature);
+static constexpr size_t kSecurityBufferLen =
+ (2 * sizeof(uint16_t)) + sizeof(uint32_t);
+static constexpr size_t kNegotiateMessageLen = 32;
+static constexpr size_t kChallengeHeaderLen = 32;
+static constexpr size_t kResponseLenV1 = 24;
+static constexpr size_t kChallengeLen = 8;
+static constexpr size_t kNtlmHashLen = 16;
+
+static constexpr NegotiateFlags kNegotiateMessageFlags =
+ NegotiateFlags::kUnicode | NegotiateFlags::kOem |
+ NegotiateFlags::kRequestTarget | NegotiateFlags::kNtlm |
+ NegotiateFlags::kAlwaysSign | NegotiateFlags::kExtendedSessionSecurity;
+
+} // namespace ntlm
+} // namespace net
+
+#endif // NET_BASE_NTLM_CONSTANTS_H_ \ No newline at end of file
diff --git a/chromium/net/ntlm/ntlm_test_data.h b/chromium/net/ntlm/ntlm_test_data.h
new file mode 100644
index 00000000000..2a9913b7a4c
--- /dev/null
+++ b/chromium/net/ntlm/ntlm_test_data.h
@@ -0,0 +1,81 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains common input and result values use to verify the NTLM
+// implementation. They are defined in [MS-NLMP] Section 4.2 [1].
+//
+// [1] https://msdn.microsoft.com/en-us/library/cc236621.aspx
+
+#ifndef NET_BASE_NTLM_TEST_DATA_H_
+#define NET_BASE_NTLM_TEST_DATA_H_
+
+#include "net/ntlm/ntlm_constants.h"
+
+namespace net {
+namespace ntlm {
+namespace test {
+
+// Common input values defined in [MS-NLMP] Section 4.2.1.
+constexpr base::char16 kPassword[] = {'P', 'a', 's', 's', 'w',
+ 'o', 'r', 'd', '\0'};
+constexpr base::char16 kNtlmDomain[] = {'D', 'o', 'm', 'a', 'i', 'n', '\0'};
+constexpr base::char16 kUser[] = {'U', 's', 'e', 'r', '\0'};
+constexpr base::char16 kHostname[] = {'C', 'O', 'M', 'P', 'U',
+ 'T', 'E', 'R', '\0'};
+
+// ASCII Versions of the above strings.
+constexpr char kNtlmDomainAscii[] = "Domain";
+constexpr char kUserAscii[] = "User";
+constexpr char kHostnameAscii[] = "COMPUTER";
+
+// Challenge vectors defined in [MS-NLMP] Section 4.2.1.
+constexpr uint8_t kServerChallenge[kChallengeLen] = {0x01, 0x23, 0x45, 0x67,
+ 0x89, 0xab, 0xcd, 0xef};
+constexpr uint8_t kClientChallenge[kChallengeLen] = {0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa};
+
+// A minimal challenge message for tests. For NTLMv1 this implementation only
+// reads the smallest required version of the message (32 bytes). Some
+// servers may still send messages this small. The only relevant flags
+// that affect behavior are that both NTLMSSP_NEGOTIATE_UNICODE and
+// NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are set.
+//
+// [0-7] - "NTLMSSP\0" (Signature)
+// [9-11] - |MessageType::kChallenge| (Message Type = 0x00000002)
+// [12-19] - |SecBuf(kNegotiateMessageLen, 0)|(Target Name - Not Used)
+// [20-23] - |NEGOTIATE_MESSAGE_FLAGS| (Flags = 0x00088207)
+// [24-31] - |SERVER_CHALLENGE| (Server Challenge)
+//
+// See [MS-NLMP] Section 2.2.2.2 for more information about the Challenge
+// message.
+constexpr uint8_t kMinChallengeMessage[kChallengeHeaderLen] = {
+ 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0', 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x07, 0x82,
+ 0x08, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+
+// Test result value for NTOWFv1() defined in [MS-NLMP] Section 4.2.2.1.2.
+constexpr uint8_t kExpectedNtlmHashV1[kNtlmHashLen] = {
+ 0xa4, 0xf4, 0x9c, 0x40, 0x65, 0x10, 0xbd, 0xca,
+ 0xb6, 0x82, 0x4e, 0xe7, 0xc3, 0x0f, 0xd8, 0x52};
+
+// Test result value defined in [MS-NLMP] Section 4.2.2.1.
+constexpr uint8_t kExpectedNtlmResponseV1[kResponseLenV1] = {
+ 0x67, 0xc4, 0x30, 0x11, 0xf3, 0x02, 0x98, 0xa2, 0xad, 0x35, 0xec, 0xe6,
+ 0x4f, 0x16, 0x33, 0x1c, 0x44, 0xbd, 0xbe, 0xd9, 0x27, 0x84, 0x1f, 0x94};
+
+// Test result value defined in [MS-NLMP] Section 4.2.3.2.2.
+constexpr uint8_t kExpectedNtlmResponseWithV1SS[kResponseLenV1] = {
+ 0x75, 0x37, 0xf8, 0x03, 0xae, 0x36, 0x71, 0x28, 0xca, 0x45, 0x82, 0x04,
+ 0xbd, 0xe7, 0xca, 0xf8, 0x1e, 0x97, 0xed, 0x26, 0x83, 0x26, 0x72, 0x32};
+
+// Test result value defined in [MS-NLMP] Section 4.2.3.2.1.
+constexpr uint8_t kExpectedLmResponseWithV1SS[kResponseLenV1] = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+} // namespace test
+} // namespace ntlm
+} // namespace net
+
+#endif // NET_BASE_NTLM_TEST_DATA_H_ \ No newline at end of file
diff --git a/chromium/net/ntlm/ntlm_unittest.cc b/chromium/net/ntlm/ntlm_unittest.cc
new file mode 100644
index 00000000000..6c40d16af6d
--- /dev/null
+++ b/chromium/net/ntlm/ntlm_unittest.cc
@@ -0,0 +1,120 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests on exact results from cryptographic operations are based on test data
+// provided in [MS-NLMP] Version 28.0 [1] Section 4.2.
+//
+// Additional sanity checks on the low level hashing operations test for
+// properties of the outputs, such as whether the hashes change, whether they
+// should be zeroed out, or whether they should be the same or different.
+//
+// [1] https://msdn.microsoft.com/en-us/library/cc236621.aspx
+
+#include "net/ntlm/ntlm.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "net/ntlm/ntlm_test_data.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace ntlm {
+
+TEST(NtlmTest, GenerateNtlmHashV1PasswordSpecTests) {
+ uint8_t hash[kNtlmHashLen];
+ GenerateNtlmHashV1(test::kPassword, hash);
+ ASSERT_EQ(0, memcmp(hash, test::kExpectedNtlmHashV1, kNtlmHashLen));
+}
+
+TEST(NtlmTest, GenerateNtlmHashV1PasswordChangesHash) {
+ base::string16 password1 = base::UTF8ToUTF16("pwd01");
+ base::string16 password2 = base::UTF8ToUTF16("pwd02");
+ uint8_t hash1[kNtlmHashLen];
+ uint8_t hash2[kNtlmHashLen];
+
+ GenerateNtlmHashV1(password1, hash1);
+ GenerateNtlmHashV1(password2, hash2);
+
+ // Verify that the hash is different with a different password.
+ ASSERT_NE(0, memcmp(hash1, hash2, kNtlmHashLen));
+}
+
+TEST(NtlmTest, GenerateResponsesV1SpecTests) {
+ uint8_t lm_response[kResponseLenV1];
+ uint8_t ntlm_response[kResponseLenV1];
+ GenerateResponsesV1(test::kPassword, test::kServerChallenge, lm_response,
+ ntlm_response);
+
+ ASSERT_EQ(
+ 0, memcmp(test::kExpectedNtlmResponseV1, ntlm_response, kResponseLenV1));
+
+ // This implementation never sends an LMv1 response (spec equivalent of the
+ // client variable NoLMResponseNTLMv1 being false) so the LM response is
+ // equal to the NTLM response when
+ // NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY is not negotiated. See
+ // [MS-NLMP] Section 3.3.1.
+ ASSERT_EQ(0,
+ memcmp(test::kExpectedNtlmResponseV1, lm_response, kResponseLenV1));
+}
+
+TEST(NtlmTest, GenerateResponsesV1WithSessionSecuritySpecTests) {
+ uint8_t lm_response[kResponseLenV1];
+ uint8_t ntlm_response[kResponseLenV1];
+ GenerateResponsesV1WithSessionSecurity(
+ test::kPassword, test::kServerChallenge, test::kClientChallenge,
+ lm_response, ntlm_response);
+
+ ASSERT_EQ(0, memcmp(test::kExpectedLmResponseWithV1SS, lm_response,
+ kResponseLenV1));
+ ASSERT_EQ(0, memcmp(test::kExpectedNtlmResponseWithV1SS, ntlm_response,
+ kResponseLenV1));
+}
+
+TEST(NtlmTest, GenerateResponsesV1WithSessionSecurityClientChallengeUsed) {
+ uint8_t lm_response1[kResponseLenV1];
+ uint8_t lm_response2[kResponseLenV1];
+ uint8_t ntlm_response1[kResponseLenV1];
+ uint8_t ntlm_response2[kResponseLenV1];
+ uint8_t client_challenge1[kChallengeLen];
+ uint8_t client_challenge2[kChallengeLen];
+
+ memset(client_challenge1, 0x01, kChallengeLen);
+ memset(client_challenge2, 0x02, kChallengeLen);
+
+ GenerateResponsesV1WithSessionSecurity(
+ test::kPassword, test::kServerChallenge, client_challenge1, lm_response1,
+ ntlm_response1);
+ GenerateResponsesV1WithSessionSecurity(
+ test::kPassword, test::kServerChallenge, client_challenge2, lm_response2,
+ ntlm_response2);
+
+ // The point of session security is that the client can introduce some
+ // randomness, so verify different client_challenge gives a different result.
+ ASSERT_NE(0, memcmp(lm_response1, lm_response2, kResponseLenV1));
+ ASSERT_NE(0, memcmp(ntlm_response1, ntlm_response2, kResponseLenV1));
+
+ // With session security the lm and ntlm hash should be different.
+ ASSERT_NE(0, memcmp(lm_response1, ntlm_response1, kResponseLenV1));
+ ASSERT_NE(0, memcmp(lm_response2, ntlm_response2, kResponseLenV1));
+}
+
+TEST(NtlmTest, GenerateResponsesV1WithSessionSecurityVerifySSUsed) {
+ uint8_t lm_response1[kResponseLenV1];
+ uint8_t lm_response2[kResponseLenV1];
+ uint8_t ntlm_response1[kResponseLenV1];
+ uint8_t ntlm_response2[kResponseLenV1];
+
+ GenerateResponsesV1WithSessionSecurity(
+ test::kPassword, test::kServerChallenge, test::kClientChallenge,
+ lm_response1, ntlm_response1);
+ GenerateResponsesV1(test::kPassword, test::kServerChallenge, lm_response2,
+ ntlm_response2);
+
+ // Verify that the responses with session security are not the
+ // same as without it.
+ ASSERT_NE(0, memcmp(lm_response1, lm_response2, kResponseLenV1));
+ ASSERT_NE(0, memcmp(ntlm_response1, ntlm_response2, kResponseLenV1));
+}
+
+} // namespace ntlm
+} // namespace net \ No newline at end of file