Bug Summary

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