Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/security/manager/ssl/./../../../../security/manager/ssl/nsNTLMAuthModule.cpp
Warning:line 377, column 3
Value stored to 'cursor' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_security_manager_ssl3.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/security/manager/ssl -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/security/manager/ssl -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D SSL_DISABLE_DEPRECATED_CIPHER_SUITE_NAMES=True -D NSS_ENABLE_ECC=True -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/security/manager/ssl -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/security/manager/ssl -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/public/nss -I /root/firefox-clang/dom/base -I /root/firefox-clang/dom/crypto -I /root/firefox-clang/netwerk/base -I /root/firefox-clang/security/certverifier -I /root/firefox-clang/third_party/rust/cose-c/include -I /root/firefox-clang/xpcom/base -I /root/firefox-clang/xpcom/build -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/toolkit/components/telemetry -I /root/firefox-clang/xpcom/base -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/gtk-3.0/unix-print -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cloudproviders -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/fribidi -I /usr/include/harfbuzz -I /usr/include/atk-1.0 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/glycin-2 -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/gio-unix-2.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -Wno-missing-field-initializers -Wno-unused-parameter -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ Unified_cpp_security_manager_ssl3.cpp
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#include "nsNTLMAuthModule.h"
6
7#include <time.h>
8
9#include "ScopedNSSTypes.h"
10#include "md4.h"
11#include "mozilla/Assertions.h"
12#include "mozilla/Base64.h"
13#include "mozilla/Casting.h"
14#include "mozilla/CheckedInt.h"
15#include "mozilla/EndianUtils.h"
16#include "mozilla/Likely.h"
17#include "mozilla/Logging.h"
18#include "mozilla/Sprintf.h"
19#include "mozilla/StaticPrefs_network.h"
20#include "mozilla/glean/SecurityManagerSslMetrics.h"
21#include "nsCOMPtr.h"
22#include "nsComponentManagerUtils.h"
23#include "nsICryptoHash.h"
24#include "nsNativeCharsetUtils.h"
25#include "nsNetCID.h"
26#include "nsUnicharUtils.h"
27#include "pk11pub.h"
28#include "prsystem.h"
29
30static mozilla::LazyLogModule sNTLMLog("NTLM");
31
32#define LOG(x)do { const ::mozilla::LogModule* moz_real_module = sNTLMLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, MOZ_LOG_EXPAND_ARGS
x); } } while (0)
MOZ_LOG(sNTLMLog, mozilla::LogLevel::Debug, x)do { const ::mozilla::LogModule* moz_real_module = sNTLMLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, MOZ_LOG_EXPAND_ARGS
x); } } while (0)
33#define LOG_ENABLED()(__builtin_expect(!!(mozilla::detail::log_test(sNTLMLog, mozilla
::LogLevel::Debug)), 0))
MOZ_LOG_TEST(sNTLMLog, mozilla::LogLevel::Debug)(__builtin_expect(!!(mozilla::detail::log_test(sNTLMLog, mozilla
::LogLevel::Debug)), 0))
34
35static void des_makekey(const uint8_t* raw, uint8_t* key);
36static void des_encrypt(const uint8_t* key, const uint8_t* src, uint8_t* hash);
37
38//-----------------------------------------------------------------------------
39// this file contains a cross-platform NTLM authentication implementation. it
40// is based on documentation from: http://davenport.sourceforge.net/ntlm.html
41//-----------------------------------------------------------------------------
42
43#define NTLM_NegotiateUnicode0x00000001 0x00000001
44#define NTLM_NegotiateOEM0x00000002 0x00000002
45#define NTLM_RequestTarget0x00000004 0x00000004
46#define NTLM_Unknown10x00000008 0x00000008
47#define NTLM_NegotiateSign0x00000010 0x00000010
48#define NTLM_NegotiateSeal0x00000020 0x00000020
49#define NTLM_NegotiateDatagramStyle0x00000040 0x00000040
50#define NTLM_NegotiateLanManagerKey0x00000080 0x00000080
51#define NTLM_NegotiateNetware0x00000100 0x00000100
52#define NTLM_NegotiateNTLMKey0x00000200 0x00000200
53#define NTLM_Unknown20x00000400 0x00000400
54#define NTLM_Unknown30x00000800 0x00000800
55#define NTLM_NegotiateDomainSupplied0x00001000 0x00001000
56#define NTLM_NegotiateWorkstationSupplied0x00002000 0x00002000
57#define NTLM_NegotiateLocalCall0x00004000 0x00004000
58#define NTLM_NegotiateAlwaysSign0x00008000 0x00008000
59#define NTLM_TargetTypeDomain0x00010000 0x00010000
60#define NTLM_TargetTypeServer0x00020000 0x00020000
61#define NTLM_TargetTypeShare0x00040000 0x00040000
62#define NTLM_NegotiateNTLM2Key0x00080000 0x00080000
63#define NTLM_RequestInitResponse0x00100000 0x00100000
64#define NTLM_RequestAcceptResponse0x00200000 0x00200000
65#define NTLM_RequestNonNTSessionKey0x00400000 0x00400000
66#define NTLM_NegotiateTargetInfo0x00800000 0x00800000
67#define NTLM_Unknown40x01000000 0x01000000
68#define NTLM_Unknown50x02000000 0x02000000
69#define NTLM_Unknown60x04000000 0x04000000
70#define NTLM_Unknown70x08000000 0x08000000
71#define NTLM_Unknown80x10000000 0x10000000
72#define NTLM_Negotiate1280x20000000 0x20000000
73#define NTLM_NegotiateKeyExchange0x40000000 0x40000000
74#define NTLM_Negotiate560x80000000 0x80000000
75
76// we send these flags with our type 1 message
77#define NTLM_TYPE1_FLAGS(0x00000001 | 0x00000002 | 0x00000004 | 0x00000200 | 0x00008000
| 0x00080000)
\
78 (NTLM_NegotiateUnicode0x00000001 | NTLM_NegotiateOEM0x00000002 | NTLM_RequestTarget0x00000004 | \
79 NTLM_NegotiateNTLMKey0x00000200 | NTLM_NegotiateAlwaysSign0x00008000 | NTLM_NegotiateNTLM2Key0x00080000)
80
81static const char NTLM_SIGNATURE[] = "NTLMSSP";
82static const char NTLM_TYPE1_MARKER[] = {0x01, 0x00, 0x00, 0x00};
83static const char NTLM_TYPE2_MARKER[] = {0x02, 0x00, 0x00, 0x00};
84static const char NTLM_TYPE3_MARKER[] = {0x03, 0x00, 0x00, 0x00};
85
86#define NTLM_TYPE1_HEADER_LEN32 32
87#define NTLM_TYPE2_HEADER_LEN48 48
88#define NTLM_TYPE3_HEADER_LEN64 64
89
90/**
91 * We don't actually send a LM response, but we still have to send something in
92 * this spot
93 */
94#define LM_RESP_LEN24 24
95
96#define NTLM_CHAL_LEN8 8
97
98#define NTLM_HASH_LEN16 16
99#define NTLMv2_HASH_LEN16 16
100#define NTLM_RESP_LEN24 24
101#define NTLMv2_RESP_LEN16 16
102#define NTLMv2_BLOB1_LEN28 28
103
104//-----------------------------------------------------------------------------
105
106/**
107 * Prints a description of flags to the NSPR Log, if enabled.
108 */
109static void LogFlags(uint32_t flags) {
110 if (!LOG_ENABLED()(__builtin_expect(!!(mozilla::detail::log_test(sNTLMLog, mozilla
::LogLevel::Debug)), 0))
) return;
111#define TEST(_flag) \
112 if (flags & NTLM_##_flag) \
113 PR_LogPrint(" 0x%08x (" #_flag ")\n", NTLM_##_flag)
114
115 TEST(NegotiateUnicode);
116 TEST(NegotiateOEM);
117 TEST(RequestTarget);
118 TEST(Unknown1);
119 TEST(NegotiateSign);
120 TEST(NegotiateSeal);
121 TEST(NegotiateDatagramStyle);
122 TEST(NegotiateLanManagerKey);
123 TEST(NegotiateNetware);
124 TEST(NegotiateNTLMKey);
125 TEST(Unknown2);
126 TEST(Unknown3);
127 TEST(NegotiateDomainSupplied);
128 TEST(NegotiateWorkstationSupplied);
129 TEST(NegotiateLocalCall);
130 TEST(NegotiateAlwaysSign);
131 TEST(TargetTypeDomain);
132 TEST(TargetTypeServer);
133 TEST(TargetTypeShare);
134 TEST(NegotiateNTLM2Key);
135 TEST(RequestInitResponse);
136 TEST(RequestAcceptResponse);
137 TEST(RequestNonNTSessionKey);
138 TEST(NegotiateTargetInfo);
139 TEST(Unknown4);
140 TEST(Unknown5);
141 TEST(Unknown6);
142 TEST(Unknown7);
143 TEST(Unknown8);
144 TEST(Negotiate128);
145 TEST(NegotiateKeyExchange);
146 TEST(Negotiate56);
147
148#undef TEST
149}
150
151/**
152 * Prints a hexdump of buf to the NSPR Log, if enabled.
153 * @param tag Description of the data, will be printed in front of the data
154 * @param buf the data to print
155 * @param bufLen length of the data
156 */
157static void LogBuf(const char* tag, const uint8_t* buf, uint32_t bufLen) {
158 int i;
159
160 if (!LOG_ENABLED()(__builtin_expect(!!(mozilla::detail::log_test(sNTLMLog, mozilla
::LogLevel::Debug)), 0))
) return;
161
162 PR_LogPrint("%s =\n", tag);
163 char line[80];
164 while (bufLen > 0) {
165 int count = bufLen;
166 if (count > 8) count = 8;
167
168 strcpy(line, " ");
169 for (i = 0; i < count; ++i) {
170 int len = strlen(line);
171 snprintf(line + len, sizeof(line) - len, "0x%02x ", int(buf[i]));
172 }
173 for (; i < 8; ++i) {
174 int len = strlen(line);
175 snprintf(line + len, sizeof(line) - len, " ");
176 }
177
178 int len = strlen(line);
179 snprintf(line + len, sizeof(line) - len, " ");
180 for (i = 0; i < count; ++i) {
181 len = strlen(line);
182 if (isprint(buf[i])) {
183 snprintf(line + len, sizeof(line) - len, "%c", buf[i]);
184 } else {
185 snprintf(line + len, sizeof(line) - len, ".");
186 }
187 }
188 PR_LogPrint("%s\n", line);
189
190 bufLen -= count;
191 buf += count;
192 }
193}
194
195/**
196 * Print base64-encoded token to the NSPR Log.
197 * @param name Description of the token, will be printed in front
198 * @param token The token to print
199 * @param tokenLen length of the data in token
200 */
201static void LogToken(const char* name, const void* token, uint32_t tokenLen) {
202 if (!LOG_ENABLED()(__builtin_expect(!!(mozilla::detail::log_test(sNTLMLog, mozilla
::LogLevel::Debug)), 0))
) {
203 return;
204 }
205
206 nsDependentCSubstring tokenString(static_cast<const char*>(token), tokenLen);
207 nsAutoCString base64Token;
208 nsresult rv = mozilla::Base64Encode(tokenString, base64Token);
209 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
210 return;
211 }
212
213 PR_LogPrint("%s: %s\n", name, base64Token.get());
214}
215
216//-----------------------------------------------------------------------------
217
218// byte order swapping
219#define SWAP16(x)((((x) & 0xff) << 8) | (((x) >> 8) & 0xff
))
((((x) & 0xff) << 8) | (((x) >> 8) & 0xff))
220#define SWAP32(x)(((((((x) & 0xffff) & 0xff) << 8) | ((((x) &
0xffff) >> 8) & 0xff)) << 16) | ((((((x) >>
16) & 0xff) << 8) | ((((x) >> 16) >> 8
) & 0xff))))
((SWAP16((x) & 0xffff)(((((x) & 0xffff) & 0xff) << 8) | ((((x) & 0xffff
) >> 8) & 0xff))
<< 16) | (SWAP16((x) >> 16)(((((x) >> 16) & 0xff) << 8) | ((((x) >>
16) >> 8) & 0xff))
))
221
222static void* WriteBytes(void* buf, const void* data, uint32_t dataLen) {
223 memcpy(buf, data, dataLen);
224 return (uint8_t*)buf + dataLen;
225}
226
227static void* WriteDWORD(void* buf, uint32_t dword) {
228#ifdef IS_BIG_ENDIAN
229 // NTLM uses little endian on the wire
230 dword = SWAP32(dword)(((((((dword) & 0xffff) & 0xff) << 8) | ((((dword
) & 0xffff) >> 8) & 0xff)) << 16) | (((((
(dword) >> 16) & 0xff) << 8) | ((((dword) >>
16) >> 8) & 0xff))))
;
231#endif
232 return WriteBytes(buf, &dword, sizeof(dword));
233}
234
235static void* WriteSecBuf(void* buf, uint16_t length, uint32_t offset) {
236#ifdef IS_BIG_ENDIAN
237 length = SWAP16(length)((((length) & 0xff) << 8) | (((length) >> 8) &
0xff))
;
238 offset = SWAP32(offset)(((((((offset) & 0xffff) & 0xff) << 8) | ((((offset
) & 0xffff) >> 8) & 0xff)) << 16) | (((((
(offset) >> 16) & 0xff) << 8) | ((((offset) >>
16) >> 8) & 0xff))))
;
239#endif
240 buf = WriteBytes(buf, &length, sizeof(length));
241 buf = WriteBytes(buf, &length, sizeof(length));
242 buf = WriteBytes(buf, &offset, sizeof(offset));
243 return buf;
244}
245
246#ifdef IS_BIG_ENDIAN
247/**
248 * WriteUnicodeLE copies a unicode string from one buffer to another. The
249 * resulting unicode string is in little-endian format. The input string is
250 * assumed to be in the native endianness of the local machine. It is safe
251 * to pass the same buffer as both input and output, which is a handy way to
252 * convert the unicode buffer to little-endian on big-endian platforms.
253 */
254static void* WriteUnicodeLE(void* buf, const char16_t* str, uint32_t strLen) {
255 // convert input string from BE to LE
256 uint8_t *cursor = (uint8_t*)buf, *input = (uint8_t*)str;
257 for (uint32_t i = 0; i < strLen; ++i, input += 2, cursor += 2) {
258 // allow for the case where |buf == str|
259 uint8_t temp = input[0];
260 cursor[0] = input[1];
261 cursor[1] = temp;
262 }
263 return buf;
264}
265#endif
266
267static uint16_t ReadUint16(const uint8_t*& buf) {
268 uint16_t x = ((uint16_t)buf[0]) | ((uint16_t)buf[1] << 8);
269 buf += sizeof(x);
270 return x;
271}
272
273static uint32_t ReadUint32(const uint8_t*& buf) {
274 uint32_t x = ((uint32_t)buf[0]) | (((uint32_t)buf[1]) << 8) |
275 (((uint32_t)buf[2]) << 16) | (((uint32_t)buf[3]) << 24);
276 buf += sizeof(x);
277 return x;
278}
279
280//-----------------------------------------------------------------------------
281
282static void ZapBuf(void* buf, size_t bufLen) { memset(buf, 0, bufLen); }
283
284static void ZapString(nsString& s) { ZapBuf(s.BeginWriting(), s.Length() * 2); }
285
286/**
287 * NTLM_Hash computes the NTLM hash of the given password.
288 *
289 * @param password
290 * null-terminated unicode password.
291 * @param hash
292 * 16-byte result buffer
293 */
294static void NTLM_Hash(const nsString& password, unsigned char* hash) {
295 uint32_t len = password.Length();
296 uint8_t* passbuf;
297
298#ifdef IS_BIG_ENDIAN
299 passbuf = (uint8_t*)malloc(len * 2);
300 WriteUnicodeLE(passbuf, password.get(), len);
301#else
302 passbuf = (uint8_t*)password.get();
303#endif
304
305 md4sum(passbuf, len * 2, hash);
306
307#ifdef IS_BIG_ENDIAN
308 ZapBuf(passbuf, len * 2);
309 free(passbuf);
310#endif
311}
312
313//-----------------------------------------------------------------------------
314
315/**
316 * LM_Response generates the LM response given a 16-byte password hash and the
317 * challenge from the Type-2 message.
318 *
319 * @param hash
320 * 16-byte password hash
321 * @param challenge
322 * 8-byte challenge from Type-2 message
323 * @param response
324 * 24-byte buffer to contain the LM response upon return
325 */
326static void LM_Response(const uint8_t* hash, const uint8_t* challenge,
327 uint8_t* response) {
328 uint8_t keybytes[21], k1[8], k2[8], k3[8];
329
330 memcpy(keybytes, hash, 16);
331 ZapBuf(keybytes + 16, 5);
332
333 des_makekey(keybytes, k1);
334 des_makekey(keybytes + 7, k2);
335 des_makekey(keybytes + 14, k3);
336
337 des_encrypt(k1, challenge, response);
338 des_encrypt(k2, challenge, response + 8);
339 des_encrypt(k3, challenge, response + 16);
340}
341
342//-----------------------------------------------------------------------------
343
344static nsresult GenerateType1Msg(void** outBuf, uint32_t* outLen) {
345 //
346 // verify that bufLen is sufficient
347 //
348 *outLen = NTLM_TYPE1_HEADER_LEN32;
349 *outBuf = moz_xmalloc(*outLen);
350
351 //
352 // write out type 1 msg
353 //
354 void* cursor = *outBuf;
355
356 // 0 : signature
357 cursor = WriteBytes(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE));
358
359 // 8 : marker
360 cursor = WriteBytes(cursor, NTLM_TYPE1_MARKER, sizeof(NTLM_TYPE1_MARKER));
361
362 // 12 : flags
363 cursor = WriteDWORD(cursor, NTLM_TYPE1_FLAGS(0x00000001 | 0x00000002 | 0x00000004 | 0x00000200 | 0x00008000
| 0x00080000)
);
364
365 //
366 // NOTE: it is common for the domain and workstation fields to be empty.
367 // this is true of Win2k clients, and my guess is that there is
368 // little utility to sending these strings before the charset has
369 // been negotiated. we follow suite -- anyways, it doesn't hurt
370 // to save some bytes on the wire ;-)
371 //
372
373 // 16 : supplied domain security buffer (empty)
374 cursor = WriteSecBuf(cursor, 0, 0);
375
376 // 24 : supplied workstation security buffer (empty)
377 cursor = WriteSecBuf(cursor, 0, 0);
Value stored to 'cursor' is never read
378
379 return NS_OK;
380}
381
382struct Type2Msg {
383 uint32_t flags; // NTLM_Xxx bitwise combination
384 uint8_t challenge[NTLM_CHAL_LEN8]; // 8 byte challenge
385 const uint8_t* target; // target string (type depends on flags)
386 uint32_t targetLen; // target length in bytes
387 const uint8_t*
388 targetInfo; // target Attribute-Value pairs (DNS domain, et al)
389 uint32_t targetInfoLen; // target AV pairs length in bytes
390};
391
392static nsresult ParseType2Msg(const void* inBuf, uint32_t inLen,
393 Type2Msg* msg) {
394 // make sure inBuf is long enough to contain a meaningful type2 msg.
395 //
396 // 0 NTLMSSP Signature
397 // 8 NTLM Message Type
398 // 12 Target Name
399 // 20 Flags
400 // 24 Challenge
401 // 32 targetInfo
402 // 48 start of optional data blocks
403 //
404 if (inLen < NTLM_TYPE2_HEADER_LEN48) return NS_ERROR_UNEXPECTED;
405
406 const auto* cursor = static_cast<const uint8_t*>(inBuf);
407
408 // verify NTLMSSP signature
409 if (memcmp(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)) != 0) {
410 return NS_ERROR_UNEXPECTED;
411 }
412
413 cursor += sizeof(NTLM_SIGNATURE);
414
415 // verify Type-2 marker
416 if (memcmp(cursor, NTLM_TYPE2_MARKER, sizeof(NTLM_TYPE2_MARKER)) != 0) {
417 return NS_ERROR_UNEXPECTED;
418 }
419
420 cursor += sizeof(NTLM_TYPE2_MARKER);
421
422 // Read target name security buffer: ...
423 // ... read target length.
424 uint32_t targetLen = ReadUint16(cursor);
425 // ... skip next 16-bit "allocated space" value.
426 ReadUint16(cursor);
427 // ... read offset from inBuf.
428 uint32_t offset = ReadUint32(cursor);
429 mozilla::CheckedInt<uint32_t> targetEnd = offset;
430 targetEnd += targetLen;
431 // Check the offset / length combo is in range of the input buffer, including
432 // integer overflow checking.
433 if (MOZ_LIKELY(targetEnd.isValid() && targetEnd.value() <= inLen)(__builtin_expect(!!(targetEnd.isValid() && targetEnd
.value() <= inLen), 1))
) {
434 msg->targetLen = targetLen;
435 msg->target = static_cast<const uint8_t*>(inBuf) + offset;
436 } else {
437 // Do not error out, for (conservative) backward compatibility.
438 msg->targetLen = 0;
439 msg->target = nullptr;
440 }
441
442 // read flags
443 msg->flags = ReadUint32(cursor);
444
445 // read challenge
446 memcpy(msg->challenge, cursor, sizeof(msg->challenge));
447 cursor += sizeof(msg->challenge);
448
449 LOG(("NTLM type 2 message:\n"))do { const ::mozilla::LogModule* moz_real_module = sNTLMLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "NTLM type 2 message:\n"
); } } while (0)
;
450 LogBuf("target", msg->target, msg->targetLen);
451 LogBuf("flags",
452 mozilla::BitwiseCast<const uint8_t*, const uint32_t*>(&msg->flags), 4);
453 LogFlags(msg->flags);
454 LogBuf("challenge", msg->challenge, sizeof(msg->challenge));
455
456 // Read (and skip) the reserved field
457 ReadUint32(cursor);
458 ReadUint32(cursor);
459 // Read target name security buffer: ...
460 // ... read target length.
461 uint32_t targetInfoLen = ReadUint16(cursor);
462 // ... skip next 16-bit "allocated space" value.
463 ReadUint16(cursor);
464 // ... read offset from inBuf.
465 offset = ReadUint32(cursor);
466 mozilla::CheckedInt<uint32_t> targetInfoEnd = offset;
467 targetInfoEnd += targetInfoLen;
468 // Check the offset / length combo is in range of the input buffer, including
469 // integer overflow checking.
470 if (MOZ_LIKELY(targetInfoEnd.isValid() && targetInfoEnd.value() <= inLen)(__builtin_expect(!!(targetInfoEnd.isValid() && targetInfoEnd
.value() <= inLen), 1))
) {
471 msg->targetInfoLen = targetInfoLen;
472 msg->targetInfo = static_cast<const uint8_t*>(inBuf) + offset;
473 } else {
474 NS_ERROR("failed to get NTLMv2 target info")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "failed to get NTLMv2 target info"
, "Error", "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp"
, 474); MOZ_PretendNoReturn(); } while (0)
;
475 return NS_ERROR_UNEXPECTED;
476 }
477
478 return NS_OK;
479}
480
481static nsresult GenerateType3Msg(const nsString& domain,
482 const nsString& username,
483 const nsString& password, const void* inBuf,
484 uint32_t inLen, void** outBuf,
485 uint32_t* outLen) {
486 // inBuf contains Type-2 msg (the challenge) from server
487 nsresult rv;
488 Type2Msg msg{};
489
490 rv = ParseType2Msg(inBuf, inLen, &msg);
491 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
492
493 bool unicode = (msg.flags & NTLM_NegotiateUnicode0x00000001);
494
495 // There is no negotiation for NTLMv2, so we just do it unless we are forced
496 // by explict user configuration to use the older DES-based cryptography.
497 bool ntlmv2 = !mozilla::StaticPrefs::network_auth_force_generic_ntlm_v1();
498
499 // temporary buffers for unicode strings
500#ifdef IS_BIG_ENDIAN
501 nsAutoString ucsDomainBuf, ucsUserBuf;
502#endif
503 nsAutoCString hostBuf;
504 nsAutoString ucsHostBuf;
505 // temporary buffers for oem strings
506 nsAutoCString oemDomainBuf, oemUserBuf, oemHostBuf;
507 // pointers and lengths for the string buffers; encoding is unicode if
508 // the "negotiate unicode" flag was set in the Type-2 message.
509 const void *domainPtr, *userPtr, *hostPtr;
510 uint32_t domainLen, userLen, hostLen;
511
512 // This is for NTLM, for NTLMv2 we set the new full length once we know it
513 mozilla::CheckedInt<uint16_t> ntlmRespLen = NTLM_RESP_LEN24;
514
515 //
516 // get domain name
517 //
518 if (unicode) {
519#ifdef IS_BIG_ENDIAN
520 ucsDomainBuf = domain;
521 domainPtr = ucsDomainBuf.get();
522 domainLen = ucsDomainBuf.Length() * 2;
523 WriteUnicodeLE(const_cast<void*>(domainPtr),
524 static_cast<const char16_t*>(domainPtr),
525 ucsDomainBuf.Length());
526#else
527 domainPtr = domain.get();
528 domainLen = domain.Length() * 2;
529#endif
530 } else {
531 NS_CopyUnicodeToNative(domain, oemDomainBuf);
532 domainPtr = oemDomainBuf.get();
533 domainLen = oemDomainBuf.Length();
534 }
535
536 //
537 // get user name
538 //
539 if (unicode) {
540#ifdef IS_BIG_ENDIAN
541 ucsUserBuf = username;
542 userPtr = ucsUserBuf.get();
543 userLen = ucsUserBuf.Length() * 2;
544 WriteUnicodeLE(const_cast<void*>(userPtr),
545 static_cast<const char16_t*>(userPtr), ucsUserBuf.Length());
546#else
547 userPtr = username.get();
548 userLen = username.Length() * 2;
549#endif
550 } else {
551 NS_CopyUnicodeToNative(username, oemUserBuf);
552 userPtr = oemUserBuf.get();
553 userLen = oemUserBuf.Length();
554 }
555
556 //
557 // get workstation name
558 // (do not use local machine's hostname after bug 1046421)
559 //
560 {
561 const auto prefLock =
562 mozilla::StaticPrefs::network_generic_ntlm_auth_workstation();
563 hostBuf = *prefLock;
564 }
565
566 if (unicode) {
567 CopyUTF8toUTF16(hostBuf, ucsHostBuf);
568 hostPtr = ucsHostBuf.get();
569 hostLen = ucsHostBuf.Length() * 2;
570#ifdef IS_BIG_ENDIAN
571 WriteUnicodeLE(const_cast<void*>(hostPtr),
572 static_cast<const char16_t*>(hostPtr), ucsHostBuf.Length());
573#endif
574 } else {
575 hostPtr = hostBuf.get();
576 hostLen = hostBuf.Length();
577 }
578
579 //
580 // now that we have generated all of the strings, we can allocate outBuf.
581 //
582 //
583 // next, we compute the NTLM or NTLM2 responses.
584 //
585 uint8_t lmResp[LM_RESP_LEN24];
586 uint8_t ntlmResp[NTLM_RESP_LEN24];
587 uint8_t ntlmv2Resp[NTLMv2_RESP_LEN16];
588 uint8_t ntlmHash[NTLM_HASH_LEN16];
589 uint8_t ntlmv2_blob1[NTLMv2_BLOB1_LEN28];
590 if (ntlmv2) {
591 // NTLMv2 mode, the default
592 nsString userUpper, domainUpper;
593
594 // temporary buffers for unicode strings
595 nsAutoString ucsDomainUpperBuf;
596 nsAutoString ucsUserUpperBuf;
597 const void* domainUpperPtr;
598 const void* userUpperPtr;
599 uint32_t domainUpperLen;
600 uint32_t userUpperLen;
601
602 if (msg.targetInfoLen == 0) {
603 NS_ERROR("failed to get NTLMv2 target info, can not do NTLMv2")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "failed to get NTLMv2 target info, can not do NTLMv2"
, "Error", "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp"
, 603); MOZ_PretendNoReturn(); } while (0)
;
604 return NS_ERROR_UNEXPECTED;
605 }
606
607 ToUpperCase(username, ucsUserUpperBuf);
608 userUpperPtr = ucsUserUpperBuf.get();
609 userUpperLen = ucsUserUpperBuf.Length() * 2;
610#ifdef IS_BIG_ENDIAN
611 WriteUnicodeLE(const_cast<void*>(userUpperPtr),
612 static_cast<const char16_t*>(userUpperPtr),
613 ucsUserUpperBuf.Length());
614#endif
615 ToUpperCase(domain, ucsDomainUpperBuf);
616 domainUpperPtr = ucsDomainUpperBuf.get();
617 domainUpperLen = ucsDomainUpperBuf.Length() * 2;
618#ifdef IS_BIG_ENDIAN
619 WriteUnicodeLE(const_cast<void*>(domainUpperPtr),
620 static_cast<const char16_t*>(domainUpperPtr),
621 ucsDomainUpperBuf.Length());
622#endif
623
624 NTLM_Hash(password, ntlmHash);
625
626 mozilla::HMAC ntlmv2HashHmac;
627 rv = ntlmv2HashHmac.Begin(SEC_OID_MD5,
628 mozilla::Span(ntlmHash, NTLM_HASH_LEN16));
629 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
630 return rv;
631 }
632 rv = ntlmv2HashHmac.Update(static_cast<const uint8_t*>(userUpperPtr),
633 userUpperLen);
634 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
635 return rv;
636 }
637 rv = ntlmv2HashHmac.Update(static_cast<const uint8_t*>(domainUpperPtr),
638 domainUpperLen);
639 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
640 return rv;
641 }
642 nsTArray<uint8_t> ntlmv2Hash;
643 rv = ntlmv2HashHmac.End(ntlmv2Hash);
644 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
645 return rv;
646 }
647
648 uint8_t client_random[NTLM_CHAL_LEN8];
649 PK11_GenerateRandom(client_random, NTLM_CHAL_LEN8);
650
651 mozilla::HMAC lmv2ResponseHmac;
652 rv = lmv2ResponseHmac.Begin(SEC_OID_MD5, mozilla::Span(ntlmv2Hash));
653 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
654 return rv;
655 }
656 rv = lmv2ResponseHmac.Update(msg.challenge, NTLM_CHAL_LEN8);
657 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
658 return rv;
659 }
660 rv = lmv2ResponseHmac.Update(client_random, NTLM_CHAL_LEN8);
661 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
662 return rv;
663 }
664 nsTArray<uint8_t> lmv2Response;
665 rv = lmv2ResponseHmac.End(lmv2Response);
666 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
667 return rv;
668 }
669
670 if (lmv2Response.Length() != NTLMv2_HASH_LEN16) {
671 return NS_ERROR_UNEXPECTED;
672 }
673
674 memcpy(lmResp, lmv2Response.Elements(), NTLMv2_HASH_LEN16);
675 memcpy(lmResp + NTLMv2_HASH_LEN16, client_random, NTLM_CHAL_LEN8);
676
677 memset(ntlmv2_blob1, 0, NTLMv2_BLOB1_LEN28);
678
679 time_t unix_time;
680 uint64_t nt_time = time(&unix_time);
681 nt_time += 11644473600LL; // Number of seconds betwen 1601 and 1970
682 nt_time *= 1000 * 1000 * 10; // Convert seconds to 100 ns units
683
684 ntlmv2_blob1[0] = 1;
685 ntlmv2_blob1[1] = 1;
686 mozilla::LittleEndian::writeUint64(&ntlmv2_blob1[8], nt_time);
687 PK11_GenerateRandom(&ntlmv2_blob1[16], NTLM_CHAL_LEN8);
688
689 mozilla::HMAC ntlmv2ResponseHmac;
690 rv = ntlmv2ResponseHmac.Begin(SEC_OID_MD5, mozilla::Span(ntlmv2Hash));
691 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
692 return rv;
693 }
694 rv = ntlmv2ResponseHmac.Update(msg.challenge, NTLM_CHAL_LEN8);
695 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
696 return rv;
697 }
698 rv = ntlmv2ResponseHmac.Update(ntlmv2_blob1, NTLMv2_BLOB1_LEN28);
699 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
700 return rv;
701 }
702 rv = ntlmv2ResponseHmac.Update(msg.targetInfo, msg.targetInfoLen);
703 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
704 return rv;
705 }
706 nsTArray<uint8_t> ntlmv2Response;
707 rv = ntlmv2ResponseHmac.End(ntlmv2Response);
708 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
709 return rv;
710 }
711
712 if (ntlmv2Response.Length() != NTLMv2_RESP_LEN16) {
713 return NS_ERROR_UNEXPECTED;
714 }
715
716 memcpy(ntlmv2Resp, ntlmv2Response.Elements(), NTLMv2_RESP_LEN16);
717 ntlmRespLen = NTLMv2_RESP_LEN16 + NTLMv2_BLOB1_LEN28;
718 ntlmRespLen += msg.targetInfoLen;
719 if (!ntlmRespLen.isValid()) {
720 NS_ERROR("failed to do NTLMv2: integer overflow?!?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "failed to do NTLMv2: integer overflow?!?"
, "Error", "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp"
, 720); MOZ_PretendNoReturn(); } while (0)
;
721 return NS_ERROR_UNEXPECTED;
722 }
723 } else if (msg.flags & NTLM_NegotiateNTLM2Key0x00080000) {
724 // compute NTLM2 session response
725 nsCString sessionHashString;
726
727 PK11_GenerateRandom(lmResp, NTLM_CHAL_LEN8);
728 memset(lmResp + NTLM_CHAL_LEN8, 0, LM_RESP_LEN24 - NTLM_CHAL_LEN8);
729
730 nsCOMPtr<nsICryptoHash> hasher =
731 do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID"@mozilla.org/security/hash;1", &rv);
732 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
733 return rv;
734 }
735 rv = hasher->Init(nsICryptoHash::MD5);
736 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
737 return rv;
738 }
739 rv = hasher->Update(msg.challenge, NTLM_CHAL_LEN8);
740 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
741 return rv;
742 }
743 rv = hasher->Update(lmResp, NTLM_CHAL_LEN8);
744 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
745 return rv;
746 }
747 rv = hasher->Finish(false, sessionHashString);
748 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
749 return rv;
750 }
751
752 const auto* sessionHash = mozilla::BitwiseCast<const uint8_t*, const char*>(
753 sessionHashString.get());
754
755 LogBuf("NTLM2 effective key: ", sessionHash, 8);
756
757 NTLM_Hash(password, ntlmHash);
758 LM_Response(ntlmHash, sessionHash, ntlmResp);
759 } else {
760 NTLM_Hash(password, ntlmHash);
761 LM_Response(ntlmHash, msg.challenge, ntlmResp);
762
763 // According to http://davenport.sourceforge.net/ntlm.html#ntlmVersion2,
764 // the correct way to not send the LM hash is to send the NTLM hash twice
765 // in both the LM and NTLM response fields.
766 LM_Response(ntlmHash, msg.challenge, lmResp);
767 }
768
769 mozilla::CheckedInt<uint32_t> totalLen = NTLM_TYPE3_HEADER_LEN64 + LM_RESP_LEN24;
770 totalLen += hostLen;
771 totalLen += domainLen;
772 totalLen += userLen;
773 totalLen += ntlmRespLen.value();
774
775 if (!totalLen.isValid()) {
776 NS_ERROR("failed preparing to allocate NTLM response: integer overflow?!?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "failed preparing to allocate NTLM response: integer overflow?!?"
, "Error", "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp"
, 776); MOZ_PretendNoReturn(); } while (0)
;
777 return NS_ERROR_FAILURE;
778 }
779 *outBuf = moz_xmalloc(totalLen.value());
780 *outLen = totalLen.value();
781
782 //
783 // finally, we assemble the Type-3 msg :-)
784 //
785 void* cursor = *outBuf;
786 mozilla::CheckedInt<uint32_t> offset;
787
788 // 0 : signature
789 cursor = WriteBytes(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE));
790
791 // 8 : marker
792 cursor = WriteBytes(cursor, NTLM_TYPE3_MARKER, sizeof(NTLM_TYPE3_MARKER));
793
794 // 12 : LM response sec buf
795 offset = NTLM_TYPE3_HEADER_LEN64;
796 offset += domainLen;
797 offset += userLen;
798 offset += hostLen;
799 if (!offset.isValid()) {
800 NS_ERROR("failed preparing to write NTLM response: integer overflow?!?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "failed preparing to write NTLM response: integer overflow?!?"
, "Error", "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp"
, 800); MOZ_PretendNoReturn(); } while (0)
;
801 return NS_ERROR_UNEXPECTED;
802 }
803 cursor = WriteSecBuf(cursor, LM_RESP_LEN24, offset.value());
804 memcpy(static_cast<uint8_t*>(*outBuf) + offset.value(), lmResp, LM_RESP_LEN24);
805
806 // 20 : NTLM or NTLMv2 response sec buf
807 offset += LM_RESP_LEN24;
808 if (!offset.isValid()) {
809 NS_ERROR("failed preparing to write NTLM response: integer overflow?!?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "failed preparing to write NTLM response: integer overflow?!?"
, "Error", "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp"
, 809); MOZ_PretendNoReturn(); } while (0)
;
810 return NS_ERROR_UNEXPECTED;
811 }
812 cursor = WriteSecBuf(cursor, ntlmRespLen.value(), offset.value());
813 if (ntlmv2) {
814 memcpy(static_cast<uint8_t*>(*outBuf) + offset.value(), ntlmv2Resp,
815 NTLMv2_RESP_LEN16);
816 offset += NTLMv2_RESP_LEN16;
817 if (!offset.isValid()) {
818 NS_ERROR("failed preparing to write NTLM response: integer overflow?!?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "failed preparing to write NTLM response: integer overflow?!?"
, "Error", "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp"
, 818); MOZ_PretendNoReturn(); } while (0)
;
819 return NS_ERROR_UNEXPECTED;
820 }
821 memcpy(static_cast<uint8_t*>(*outBuf) + offset.value(), ntlmv2_blob1,
822 NTLMv2_BLOB1_LEN28);
823 offset += NTLMv2_BLOB1_LEN28;
824 if (!offset.isValid()) {
825 NS_ERROR("failed preparing to write NTLM response: integer overflow?!?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "failed preparing to write NTLM response: integer overflow?!?"
, "Error", "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp"
, 825); MOZ_PretendNoReturn(); } while (0)
;
826 return NS_ERROR_UNEXPECTED;
827 }
828 memcpy(static_cast<uint8_t*>(*outBuf) + offset.value(), msg.targetInfo,
829 msg.targetInfoLen);
830 } else {
831 memcpy(static_cast<uint8_t*>(*outBuf) + offset.value(), ntlmResp,
832 NTLM_RESP_LEN24);
833 }
834 // 28 : domain name sec buf
835 offset = NTLM_TYPE3_HEADER_LEN64;
836 cursor = WriteSecBuf(cursor, domainLen, offset.value());
837 memcpy(static_cast<uint8_t*>(*outBuf) + offset.value(), domainPtr, domainLen);
838
839 // 36 : user name sec buf
840 offset += domainLen;
841 if (!offset.isValid()) {
842 NS_ERROR("failed preparing to write NTLM response: integer overflow?!?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "failed preparing to write NTLM response: integer overflow?!?"
, "Error", "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp"
, 842); MOZ_PretendNoReturn(); } while (0)
;
843 return NS_ERROR_UNEXPECTED;
844 }
845 cursor = WriteSecBuf(cursor, userLen, offset.value());
846 memcpy(static_cast<uint8_t*>(*outBuf) + offset.value(), userPtr, userLen);
847
848 // 44 : workstation (host) name sec buf
849 offset += userLen;
850 if (!offset.isValid()) {
851 NS_ERROR("failed preparing to write NTLM response: integer overflow?!?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "failed preparing to write NTLM response: integer overflow?!?"
, "Error", "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp"
, 851); MOZ_PretendNoReturn(); } while (0)
;
852 return NS_ERROR_UNEXPECTED;
853 }
854 cursor = WriteSecBuf(cursor, hostLen, offset.value());
855 memcpy(static_cast<uint8_t*>(*outBuf) + offset.value(), hostPtr, hostLen);
856
857 // 52 : session key sec buf (not used)
858 cursor = WriteSecBuf(cursor, 0, 0);
859
860 // 60 : negotiated flags
861 cursor = WriteDWORD(cursor, msg.flags & NTLM_TYPE1_FLAGS(0x00000001 | 0x00000002 | 0x00000004 | 0x00000200 | 0x00008000
| 0x00080000)
);
862
863 return NS_OK;
864}
865
866//-----------------------------------------------------------------------------
867
868NS_IMPL_ISUPPORTS(nsNTLMAuthModule, nsIAuthModule)MozExternalRefCountType nsNTLMAuthModule::AddRef(void) { static_assert
(!std::is_destructible_v<nsNTLMAuthModule>, "Reference-counted class "
"nsNTLMAuthModule" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp"
, 868); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 868
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsNTLMAuthModule" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsNTLMAuthModule" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsNTLMAuthModule\" != nullptr" " (" "Must specify a name" ")"
, "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp", 868
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsNTLMAuthModule\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 868); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsNTLMAuthModule" " not thread-safe"); nsrefcnt count = ++mRefCnt
; NS_LogAddRef((this), (count), ("nsNTLMAuthModule"), (uint32_t
)(sizeof(*this))); return count; } MozExternalRefCountType nsNTLMAuthModule
::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp"
, 868); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 868
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsNTLMAuthModule" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsNTLMAuthModule" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsNTLMAuthModule\" != nullptr" " (" "Must specify a name" ")"
, "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp", 868
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsNTLMAuthModule\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 868); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsNTLMAuthModule" " not thread-safe"); const char* const nametmp
= "nsNTLMAuthModule"; nsrefcnt count = --mRefCnt; NS_LogRelease
((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete
(this); return 0; } return count; } nsresult nsNTLMAuthModule
::QueryInterface(const nsIID& aIID, void** aInstancePtr) {
do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "QueryInterface requires a non-NULL destination!", "aInstancePtr"
, "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp", 868
); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<nsNTLMAuthModule, nsIAuthModule>, int32_t
( reinterpret_cast<char*>(static_cast<nsIAuthModule*
>((nsNTLMAuthModule*)0x1000)) - reinterpret_cast<char*>
((nsNTLMAuthModule*)0x1000))}, {&mozilla::detail::kImplementedIID
<nsNTLMAuthModule, nsISupports>, int32_t(reinterpret_cast
<char*>(static_cast<nsISupports*>( static_cast<
nsIAuthModule*>((nsNTLMAuthModule*)0x1000))) - reinterpret_cast
<char*>((nsNTLMAuthModule*)0x1000))}, { nullptr, 0 } } ;
static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
869
870nsNTLMAuthModule::~nsNTLMAuthModule() { ZapString(mPassword); }
871
872nsresult nsNTLMAuthModule::InitTest() {
873 // disable NTLM authentication when FIPS mode is enabled.
874 return PK11_IsFIPS() ? NS_ERROR_NOT_AVAILABLE : NS_OK;
875}
876
877NS_IMETHODIMPnsresult
878nsNTLMAuthModule::Init(const nsACString& serviceName, uint32_t serviceFlags,
879 const nsAString& domain, const nsAString& username,
880 const nsAString& password) {
881 MOZ_ASSERT((serviceFlags & ~nsIAuthModule::REQ_PROXY_AUTH) ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype((serviceFlags & ~nsIAuthModule::REQ_PROXY_AUTH) ==
nsIAuthModule::REQ_DEFAULT)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((serviceFlags & ~nsIAuthModule
::REQ_PROXY_AUTH) == nsIAuthModule::REQ_DEFAULT))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("(serviceFlags & ~nsIAuthModule::REQ_PROXY_AUTH) == nsIAuthModule::REQ_DEFAULT"
" (" "Unexpected service flags" ")", "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp"
, 883); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(serviceFlags & ~nsIAuthModule::REQ_PROXY_AUTH) == nsIAuthModule::REQ_DEFAULT"
") (" "Unexpected service flags" ")"); do { MOZ_CrashSequence
(__null, 883); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
882 nsIAuthModule::REQ_DEFAULT,do { static_assert( mozilla::detail::AssertionConditionType<
decltype((serviceFlags & ~nsIAuthModule::REQ_PROXY_AUTH) ==
nsIAuthModule::REQ_DEFAULT)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((serviceFlags & ~nsIAuthModule
::REQ_PROXY_AUTH) == nsIAuthModule::REQ_DEFAULT))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("(serviceFlags & ~nsIAuthModule::REQ_PROXY_AUTH) == nsIAuthModule::REQ_DEFAULT"
" (" "Unexpected service flags" ")", "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp"
, 883); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(serviceFlags & ~nsIAuthModule::REQ_PROXY_AUTH) == nsIAuthModule::REQ_DEFAULT"
") (" "Unexpected service flags" ")"); do { MOZ_CrashSequence
(__null, 883); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
883 "Unexpected service flags")do { static_assert( mozilla::detail::AssertionConditionType<
decltype((serviceFlags & ~nsIAuthModule::REQ_PROXY_AUTH) ==
nsIAuthModule::REQ_DEFAULT)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((serviceFlags & ~nsIAuthModule
::REQ_PROXY_AUTH) == nsIAuthModule::REQ_DEFAULT))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("(serviceFlags & ~nsIAuthModule::REQ_PROXY_AUTH) == nsIAuthModule::REQ_DEFAULT"
" (" "Unexpected service flags" ")", "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp"
, 883); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(serviceFlags & ~nsIAuthModule::REQ_PROXY_AUTH) == nsIAuthModule::REQ_DEFAULT"
") (" "Unexpected service flags" ")"); do { MOZ_CrashSequence
(__null, 883); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
884
885 mDomain = domain;
886 mUsername = username;
887 mPassword = password;
888 mNTLMNegotiateSent = false;
889
890 static bool sTelemetrySent = false;
891 if (!sTelemetrySent) {
892 mozilla::glean::security::ntlm_module_used.AccumulateSingleSample(
893 serviceFlags & nsIAuthModule::REQ_PROXY_AUTH
894 ? NTLM_MODULE_GENERIC_PROXY
895 : NTLM_MODULE_GENERIC_DIRECT);
896 sTelemetrySent = true;
897 }
898
899 return NS_OK;
900}
901
902NS_IMETHODIMPnsresult
903nsNTLMAuthModule::GetNextToken(const void* inToken, uint32_t inTokenLen,
904 void** outToken, uint32_t* outTokenLen) {
905 nsresult rv;
906
907 // disable NTLM authentication when FIPS mode is enabled.
908 if (PK11_IsFIPS()) {
909 return NS_ERROR_NOT_AVAILABLE;
910 }
911
912 if (mNTLMNegotiateSent) {
913 // if inToken is non-null, and we have sent the NTLMSSP_NEGOTIATE (type 1),
914 // then the NTLMSSP_CHALLENGE (type 2) is expected
915 if (inToken) {
916 LogToken("in-token", inToken, inTokenLen);
917 // Now generate the NTLMSSP_AUTH (type 3)
918 rv = GenerateType3Msg(mDomain, mUsername, mPassword, inToken, inTokenLen,
919 outToken, outTokenLen);
920 } else {
921 LOG(do { const ::mozilla::LogModule* moz_real_module = sNTLMLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "NTLMSSP_NEGOTIATE already sent and presumably "
"rejected by the server, refusing to send another"); } } while
(0)
922 ("NTLMSSP_NEGOTIATE already sent and presumably "do { const ::mozilla::LogModule* moz_real_module = sNTLMLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "NTLMSSP_NEGOTIATE already sent and presumably "
"rejected by the server, refusing to send another"); } } while
(0)
923 "rejected by the server, refusing to send another"))do { const ::mozilla::LogModule* moz_real_module = sNTLMLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "NTLMSSP_NEGOTIATE already sent and presumably "
"rejected by the server, refusing to send another"); } } while
(0)
;
924 rv = NS_ERROR_UNEXPECTED;
925 }
926 } else {
927 if (inToken) {
928 LOG(("NTLMSSP_NEGOTIATE not sent but NTLM reply already received?!?"))do { const ::mozilla::LogModule* moz_real_module = sNTLMLog; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "NTLMSSP_NEGOTIATE not sent but NTLM reply already received?!?"
); } } while (0)
;
929 rv = NS_ERROR_UNEXPECTED;
930 } else {
931 rv = GenerateType1Msg(outToken, outTokenLen);
932 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
933 mNTLMNegotiateSent = true;
934 }
935 }
936 }
937
938 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) LogToken("out-token", *outToken, *outTokenLen);
939
940 return rv;
941}
942
943NS_IMETHODIMPnsresult
944nsNTLMAuthModule::Unwrap(const void* inToken, uint32_t inTokenLen,
945 void** outToken, uint32_t* outTokenLen) {
946 return NS_ERROR_NOT_IMPLEMENTED;
947}
948
949NS_IMETHODIMPnsresult
950nsNTLMAuthModule::Wrap(const void* inToken, uint32_t inTokenLen,
951 bool confidential, void** outToken,
952 uint32_t* outTokenLen) {
953 return NS_ERROR_NOT_IMPLEMENTED;
954}
955
956//-----------------------------------------------------------------------------
957// DES support code
958
959// set odd parity bit (in least significant bit position)
960static uint8_t des_setkeyparity(uint8_t x) {
961 if ((((x >> 7) ^ (x >> 6) ^ (x >> 5) ^ (x >> 4) ^ (x >> 3) ^ (x >> 2) ^
962 (x >> 1)) &
963 0x01) == 0) {
964 x |= 0x01;
965 } else {
966 x &= 0xfe;
967 }
968 return x;
969}
970
971// build 64-bit des key from 56-bit raw key
972static void des_makekey(const uint8_t* raw, uint8_t* key) {
973 key[0] = des_setkeyparity(raw[0]);
974 key[1] = des_setkeyparity((raw[0] << 7) | (raw[1] >> 1));
975 key[2] = des_setkeyparity((raw[1] << 6) | (raw[2] >> 2));
976 key[3] = des_setkeyparity((raw[2] << 5) | (raw[3] >> 3));
977 key[4] = des_setkeyparity((raw[3] << 4) | (raw[4] >> 4));
978 key[5] = des_setkeyparity((raw[4] << 3) | (raw[5] >> 5));
979 key[6] = des_setkeyparity((raw[5] << 2) | (raw[6] >> 6));
980 key[7] = des_setkeyparity((raw[6] << 1));
981}
982
983// run des encryption algorithm (using NSS)
984static void des_encrypt(const uint8_t* key, const uint8_t* src, uint8_t* hash) {
985 CK_MECHANISM_TYPE cipherMech = CKM_DES_ECB0x00000121UL;
986 PK11SymKey* symkey = nullptr;
987 PK11Context* ctxt = nullptr;
988 SECItem keyItem;
989 mozilla::UniqueSECItem param;
990 SECStatus rv;
991 unsigned int n;
992
993 mozilla::UniquePK11SlotInfo slot(PK11_GetBestSlot(cipherMech, nullptr));
994 if (!slot) {
995 NS_ERROR("no slot")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "no slot", "Error", "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp"
, 995); MOZ_PretendNoReturn(); } while (0)
;
996 goto done;
997 }
998
999 keyItem.data = const_cast<uint8_t*>(key);
1000 keyItem.len = 8;
1001 symkey = PK11_ImportSymKey(slot.get(), cipherMech, PK11_OriginUnwrap,
1002 CKA_ENCRYPT0x00000104UL, &keyItem, nullptr);
1003 if (!symkey) {
1004 NS_ERROR("no symkey")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "no symkey", "Error", "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp"
, 1004); MOZ_PretendNoReturn(); } while (0)
;
1005 goto done;
1006 }
1007
1008 // no initialization vector required
1009 param = mozilla::UniqueSECItem(PK11_ParamFromIV(cipherMech, nullptr));
1010 if (!param) {
1011 NS_ERROR("no param")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "no param", "Error", "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp"
, 1011); MOZ_PretendNoReturn(); } while (0)
;
1012 goto done;
1013 }
1014
1015 ctxt =
1016 PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT0x00000104UL, symkey, param.get());
1017 if (!ctxt) {
1018 NS_ERROR("no context")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "no context", "Error",
"./../../../../security/manager/ssl/nsNTLMAuthModule.cpp", 1018
); MOZ_PretendNoReturn(); } while (0)
;
1019 goto done;
1020 }
1021
1022 rv = PK11_CipherOp(ctxt, hash, (int*)&n, 8, (uint8_t*)src, 8);
1023 if (rv != SECSuccess) {
1024 NS_ERROR("des failure")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "des failure", "Error"
, "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp", 1024
); MOZ_PretendNoReturn(); } while (0)
;
1025 goto done;
1026 }
1027
1028 rv = PK11_DigestFinal(ctxt, hash + 8, &n, 0);
1029 if (rv != SECSuccess) {
1030 NS_ERROR("des failure")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "des failure", "Error"
, "./../../../../security/manager/ssl/nsNTLMAuthModule.cpp", 1030
); MOZ_PretendNoReturn(); } while (0)
;
1031 goto done;
1032 }
1033
1034done:
1035 if (ctxt) PK11_DestroyContext(ctxt, true);
1036 if (symkey) PK11_FreeSymKey(symkey);
1037}