LCOV - code coverage report
Current view: top level - security/manager/ssl - nsNTLMAuthModule.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 490 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 28 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13