Bug Summary

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