LCOV - code coverage report
Current view: directory - security/manager/ssl/src - nsNTLMAuthModule.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 331 15 4.5 %
Date: 2012-06-02 Functions: 35 10 28.6 %

       1                 : /* vim:set ts=2 sw=2 et cindent: */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is IBM Corporation.
      18                 :  * Portions created by IBM Corporation are Copyright (C) 2003
      19                 :  * IBM Corporation. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Darin Fisher <darin@meer.net>
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "prlog.h"
      39                 : 
      40                 : #include <stdlib.h>
      41                 : #include "nsIPrefService.h"
      42                 : #include "nsIPrefBranch.h"
      43                 : #include "nsServiceManagerUtils.h"
      44                 : #include "nsCOMPtr.h"
      45                 : #include "nsNSSShutDown.h"
      46                 : #include "nsNTLMAuthModule.h"
      47                 : #include "nsNativeCharsetUtils.h"
      48                 : #include "nsReadableUtils.h"
      49                 : #include "nsString.h"
      50                 : #include "prsystem.h"
      51                 : #include "nss.h"
      52                 : #include "pk11func.h"
      53                 : #include "md4.h"
      54                 : 
      55                 : #ifdef PR_LOGGING
      56            1464 : PRLogModuleInfo *gNTLMLog = PR_NewLogModule("NTLM");
      57                 : 
      58                 : #define LOG(x) PR_LOG(gNTLMLog, PR_LOG_DEBUG, x)
      59                 : #define LOG_ENABLED() PR_LOG_TEST(gNTLMLog, PR_LOG_DEBUG)
      60                 : #else
      61                 : #define LOG(x)
      62                 : #endif
      63                 : 
      64                 : static void des_makekey(const PRUint8 *raw, PRUint8 *key);
      65                 : static void des_encrypt(const PRUint8 *key, const PRUint8 *src, PRUint8 *hash);
      66                 : static void md5sum(const PRUint8 *input, PRUint32 inputLen, PRUint8 *result);
      67                 : 
      68                 : //-----------------------------------------------------------------------------
      69                 : // this file contains a cross-platform NTLM authentication implementation. it
      70                 : // is based on documentation from: http://davenport.sourceforge.net/ntlm.html
      71                 : //-----------------------------------------------------------------------------
      72                 : 
      73                 : #define NTLM_NegotiateUnicode               0x00000001
      74                 : #define NTLM_NegotiateOEM                   0x00000002
      75                 : #define NTLM_RequestTarget                  0x00000004
      76                 : #define NTLM_Unknown1                       0x00000008
      77                 : #define NTLM_NegotiateSign                  0x00000010
      78                 : #define NTLM_NegotiateSeal                  0x00000020
      79                 : #define NTLM_NegotiateDatagramStyle         0x00000040
      80                 : #define NTLM_NegotiateLanManagerKey         0x00000080
      81                 : #define NTLM_NegotiateNetware               0x00000100
      82                 : #define NTLM_NegotiateNTLMKey               0x00000200
      83                 : #define NTLM_Unknown2                       0x00000400
      84                 : #define NTLM_Unknown3                       0x00000800
      85                 : #define NTLM_NegotiateDomainSupplied        0x00001000
      86                 : #define NTLM_NegotiateWorkstationSupplied   0x00002000
      87                 : #define NTLM_NegotiateLocalCall             0x00004000
      88                 : #define NTLM_NegotiateAlwaysSign            0x00008000
      89                 : #define NTLM_TargetTypeDomain               0x00010000
      90                 : #define NTLM_TargetTypeServer               0x00020000
      91                 : #define NTLM_TargetTypeShare                0x00040000
      92                 : #define NTLM_NegotiateNTLM2Key              0x00080000
      93                 : #define NTLM_RequestInitResponse            0x00100000
      94                 : #define NTLM_RequestAcceptResponse          0x00200000
      95                 : #define NTLM_RequestNonNTSessionKey         0x00400000
      96                 : #define NTLM_NegotiateTargetInfo            0x00800000
      97                 : #define NTLM_Unknown4                       0x01000000
      98                 : #define NTLM_Unknown5                       0x02000000
      99                 : #define NTLM_Unknown6                       0x04000000
     100                 : #define NTLM_Unknown7                       0x08000000
     101                 : #define NTLM_Unknown8                       0x10000000
     102                 : #define NTLM_Negotiate128                   0x20000000
     103                 : #define NTLM_NegotiateKeyExchange           0x40000000
     104                 : #define NTLM_Negotiate56                    0x80000000
     105                 : 
     106                 : // we send these flags with our type 1 message
     107                 : #define NTLM_TYPE1_FLAGS      \
     108                 :   (NTLM_NegotiateUnicode |    \
     109                 :    NTLM_NegotiateOEM |        \
     110                 :    NTLM_RequestTarget |       \
     111                 :    NTLM_NegotiateNTLMKey |    \
     112                 :    NTLM_NegotiateAlwaysSign | \
     113                 :    NTLM_NegotiateNTLM2Key)
     114                 : 
     115                 : static const char NTLM_SIGNATURE[] = "NTLMSSP";
     116                 : static const char NTLM_TYPE1_MARKER[] = { 0x01, 0x00, 0x00, 0x00 };
     117                 : static const char NTLM_TYPE2_MARKER[] = { 0x02, 0x00, 0x00, 0x00 };
     118                 : static const char NTLM_TYPE3_MARKER[] = { 0x03, 0x00, 0x00, 0x00 };
     119                 : 
     120                 : #define NTLM_TYPE1_HEADER_LEN 32
     121                 : #define NTLM_TYPE2_HEADER_LEN 32
     122                 : #define NTLM_TYPE3_HEADER_LEN 64
     123                 : 
     124                 : #define LM_HASH_LEN 16
     125                 : #define LM_RESP_LEN 24
     126                 : 
     127                 : #define NTLM_HASH_LEN 16
     128                 : #define NTLM_RESP_LEN 24
     129                 : 
     130                 : //-----------------------------------------------------------------------------
     131                 : 
     132               0 : static bool SendLM()
     133                 : {
     134               0 :   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
     135               0 :   if (!prefs)
     136               0 :     return false;
     137                 : 
     138                 :   bool val;
     139               0 :   nsresult rv = prefs->GetBoolPref("network.ntlm.send-lm-response", &val);
     140               0 :   return NS_SUCCEEDED(rv) && val;
     141                 : }
     142                 : 
     143                 : //-----------------------------------------------------------------------------
     144                 : 
     145                 : #ifdef PR_LOGGING
     146                 : 
     147                 : /**
     148                 :  * Prints a description of flags to the NSPR Log, if enabled.
     149                 :  */
     150               0 : static void LogFlags(PRUint32 flags)
     151                 : {
     152               0 :   if (!LOG_ENABLED())
     153               0 :     return;
     154                 : #define TEST(_flag) \
     155                 :   if (flags & NTLM_ ## _flag) \
     156                 :     PR_LogPrint("    0x%08x (" # _flag ")\n", NTLM_ ## _flag)
     157                 : 
     158               0 :   TEST(NegotiateUnicode);
     159               0 :   TEST(NegotiateOEM);
     160               0 :   TEST(RequestTarget);
     161               0 :   TEST(Unknown1);
     162               0 :   TEST(NegotiateSign);
     163               0 :   TEST(NegotiateSeal);
     164               0 :   TEST(NegotiateDatagramStyle);
     165               0 :   TEST(NegotiateLanManagerKey);
     166               0 :   TEST(NegotiateNetware);
     167               0 :   TEST(NegotiateNTLMKey);
     168               0 :   TEST(Unknown2);
     169               0 :   TEST(Unknown3);
     170               0 :   TEST(NegotiateDomainSupplied);
     171               0 :   TEST(NegotiateWorkstationSupplied);
     172               0 :   TEST(NegotiateLocalCall);
     173               0 :   TEST(NegotiateAlwaysSign);
     174               0 :   TEST(TargetTypeDomain);
     175               0 :   TEST(TargetTypeServer);
     176               0 :   TEST(TargetTypeShare);
     177               0 :   TEST(NegotiateNTLM2Key);
     178               0 :   TEST(RequestInitResponse);
     179               0 :   TEST(RequestAcceptResponse);
     180               0 :   TEST(RequestNonNTSessionKey);
     181               0 :   TEST(NegotiateTargetInfo);
     182               0 :   TEST(Unknown4);
     183               0 :   TEST(Unknown5);
     184               0 :   TEST(Unknown6);
     185               0 :   TEST(Unknown7);
     186               0 :   TEST(Unknown8);
     187               0 :   TEST(Negotiate128);
     188               0 :   TEST(NegotiateKeyExchange);
     189               0 :   TEST(Negotiate56);
     190                 : 
     191                 : #undef TEST
     192                 : }
     193                 : 
     194                 : /**
     195                 :  * Prints a hexdump of buf to the NSPR Log, if enabled.
     196                 :  * @param tag Description of the data, will be printed in front of the data
     197                 :  * @param buf the data to print
     198                 :  * @param bufLen length of the data
     199                 :  */
     200                 : static void
     201               0 : LogBuf(const char *tag, const PRUint8 *buf, PRUint32 bufLen)
     202                 : {
     203                 :   int i;
     204                 : 
     205               0 :   if (!LOG_ENABLED())
     206               0 :     return;
     207                 : 
     208               0 :   PR_LogPrint("%s =\n", tag);
     209                 :   char line[80];
     210               0 :   while (bufLen > 0)
     211                 :   {
     212               0 :     int count = bufLen;
     213               0 :     if (count > 8)
     214               0 :       count = 8;
     215                 : 
     216               0 :     strcpy(line, "    ");
     217               0 :     for (i=0; i<count; ++i)
     218                 :     {
     219               0 :       int len = strlen(line);
     220               0 :       PR_snprintf(line + len, sizeof(line) - len, "0x%02x ", int(buf[i]));
     221                 :     }
     222               0 :     for (; i<8; ++i)
     223                 :     {
     224               0 :       int len = strlen(line);
     225               0 :       PR_snprintf(line + len, sizeof(line) - len, "     ");
     226                 :     }
     227                 : 
     228               0 :     int len = strlen(line);
     229               0 :     PR_snprintf(line + len, sizeof(line) - len, "   ");
     230               0 :     for (i=0; i<count; ++i)
     231                 :     {
     232               0 :       len = strlen(line);
     233               0 :       if (isprint(buf[i]))
     234               0 :         PR_snprintf(line + len, sizeof(line) - len, "%c", buf[i]);
     235                 :       else
     236               0 :         PR_snprintf(line + len, sizeof(line) - len, ".");
     237                 :     }
     238               0 :     PR_LogPrint("%s\n", line);
     239                 : 
     240               0 :     bufLen -= count;
     241               0 :     buf += count;
     242                 :   }
     243                 : }
     244                 : 
     245                 : #include "plbase64.h"
     246                 : #include "prmem.h"
     247                 : /**
     248                 :  * Print base64-encoded token to the NSPR Log.
     249                 :  * @param name Description of the token, will be printed in front
     250                 :  * @param token The token to print
     251                 :  * @param tokenLen length of the data in token
     252                 :  */
     253               0 : static void LogToken(const char *name, const void *token, PRUint32 tokenLen)
     254                 : {
     255               0 :   if (!LOG_ENABLED())
     256               0 :     return;
     257                 : 
     258               0 :   char *b64data = PL_Base64Encode((const char *) token, tokenLen, NULL);
     259               0 :   if (b64data)
     260                 :   {
     261               0 :     PR_LogPrint("%s: %s\n", name, b64data);
     262               0 :     PR_Free(b64data);
     263                 :   }
     264                 : }
     265                 : 
     266                 : #else
     267                 : #define LogFlags(x)
     268                 : #define LogBuf(a,b,c)
     269                 : #define LogToken(a,b,c)
     270                 : 
     271                 : #endif // PR_LOGGING
     272                 : 
     273                 : //-----------------------------------------------------------------------------
     274                 : 
     275                 : // byte order swapping
     276                 : #define SWAP16(x) ((((x) & 0xff) << 8) | (((x) >> 8) & 0xff))
     277                 : #define SWAP32(x) ((SWAP16((x) & 0xffff) << 16) | (SWAP16((x) >> 16)))
     278                 : 
     279                 : static void *
     280               0 : WriteBytes(void *buf, const void *data, PRUint32 dataLen)
     281                 : {
     282               0 :   memcpy(buf, data, dataLen);
     283               0 :   return (PRUint8 *) buf + dataLen;
     284                 : }
     285                 : 
     286                 : static void *
     287               0 : WriteDWORD(void *buf, PRUint32 dword)
     288                 : {
     289                 : #ifdef IS_BIG_ENDIAN 
     290                 :   // NTLM uses little endian on the wire
     291                 :   dword = SWAP32(dword);
     292                 : #endif
     293               0 :   return WriteBytes(buf, &dword, sizeof(dword));
     294                 : }
     295                 : 
     296                 : static void *
     297               0 : WriteSecBuf(void *buf, PRUint16 length, PRUint32 offset)
     298                 : {
     299                 : #ifdef IS_BIG_ENDIAN
     300                 :   length = SWAP16(length);
     301                 :   offset = SWAP32(offset);
     302                 : #endif
     303               0 :   buf = WriteBytes(buf, &length, sizeof(length));
     304               0 :   buf = WriteBytes(buf, &length, sizeof(length));
     305               0 :   buf = WriteBytes(buf, &offset, sizeof(offset));
     306               0 :   return buf;
     307                 : }
     308                 : 
     309                 : #ifdef IS_BIG_ENDIAN
     310                 : /**
     311                 :  * WriteUnicodeLE copies a unicode string from one buffer to another.  The
     312                 :  * resulting unicode string is in little-endian format.  The input string is
     313                 :  * assumed to be in the native endianness of the local machine.  It is safe
     314                 :  * to pass the same buffer as both input and output, which is a handy way to
     315                 :  * convert the unicode buffer to little-endian on big-endian platforms.
     316                 :  */
     317                 : static void *
     318                 : WriteUnicodeLE(void *buf, const PRUnichar *str, PRUint32 strLen)
     319                 : {
     320                 :   // convert input string from BE to LE
     321                 :   PRUint8 *cursor = (PRUint8 *) buf,
     322                 :           *input  = (PRUint8 *) str;
     323                 :   for (PRUint32 i=0; i<strLen; ++i, input+=2, cursor+=2)
     324                 :   {
     325                 :     // allow for the case where |buf == str|
     326                 :     PRUint8 temp = input[0];
     327                 :     cursor[0] = input[1];
     328                 :     cursor[1] = temp;
     329                 :   }
     330                 :   return buf;
     331                 : }
     332                 : #endif
     333                 : 
     334                 : static PRUint16
     335               0 : ReadUint16(const PRUint8 *&buf)
     336                 : {
     337               0 :   PRUint16 x = ((PRUint16) buf[0]) | ((PRUint16) buf[1] << 8);
     338               0 :   buf += sizeof(x);
     339               0 :   return x;
     340                 : }
     341                 : 
     342                 : static PRUint32
     343               0 : ReadUint32(const PRUint8 *&buf)
     344                 : {
     345               0 :   PRUint32 x = ( (PRUint32) buf[0])        |
     346               0 :                (((PRUint32) buf[1]) << 8)  |
     347               0 :                (((PRUint32) buf[2]) << 16) |
     348               0 :                (((PRUint32) buf[3]) << 24);
     349               0 :   buf += sizeof(x);
     350               0 :   return x;
     351                 : }
     352                 : 
     353                 : //-----------------------------------------------------------------------------
     354                 : 
     355                 : static void
     356               1 : ZapBuf(void *buf, size_t bufLen)
     357                 : {
     358               1 :   memset(buf, 0, bufLen);
     359               1 : }
     360                 : 
     361                 : static void
     362               0 : ZapString(nsCString &s)
     363                 : {
     364               0 :   ZapBuf(s.BeginWriting(), s.Length());
     365               0 : }
     366                 : 
     367                 : static void
     368               1 : ZapString(nsString &s)
     369                 : {
     370               1 :   ZapBuf(s.BeginWriting(), s.Length() * 2);
     371               1 : }
     372                 : 
     373                 : static const unsigned char LM_MAGIC[] = "KGS!@#$%";
     374                 : 
     375                 : /**
     376                 :  * LM_Hash computes the LM hash of the given password.
     377                 :  *
     378                 :  * @param password
     379                 :  *        null-terminated unicode password.
     380                 :  * @param hash
     381                 :  *        16-byte result buffer
     382                 :  */
     383                 : static void
     384               0 : LM_Hash(const nsString &password, unsigned char *hash)
     385                 : {
     386                 :   // convert password to OEM character set.  we'll just use the native
     387                 :   // filesystem charset.
     388               0 :   nsCAutoString passbuf;
     389               0 :   NS_CopyUnicodeToNative(password, passbuf);
     390               0 :   ToUpperCase(passbuf);
     391               0 :   PRUint32 n = passbuf.Length();
     392               0 :   passbuf.SetLength(14);
     393               0 :   for (PRUint32 i=n; i<14; ++i)
     394               0 :     passbuf.SetCharAt('\0', i);
     395                 : 
     396                 :   unsigned char k1[8], k2[8];
     397               0 :   des_makekey((const unsigned char *) passbuf.get()    , k1);
     398               0 :   des_makekey((const unsigned char *) passbuf.get() + 7, k2);
     399               0 :   ZapString(passbuf);
     400                 : 
     401                 :   // use password keys to hash LM magic string twice.
     402               0 :   des_encrypt(k1, LM_MAGIC, hash);
     403               0 :   des_encrypt(k2, LM_MAGIC, hash + 8);
     404               0 : }
     405                 : 
     406                 : /**
     407                 :  * NTLM_Hash computes the NTLM hash of the given password.
     408                 :  *
     409                 :  * @param password
     410                 :  *        null-terminated unicode password.
     411                 :  * @param hash
     412                 :  *        16-byte result buffer
     413                 :  */
     414                 : static void
     415               0 : NTLM_Hash(const nsString &password, unsigned char *hash)
     416                 : {
     417               0 :   PRUint32 len = password.Length();
     418                 :   PRUint8 *passbuf;
     419                 :   
     420                 : #ifdef IS_BIG_ENDIAN
     421                 :   passbuf = (PRUint8 *) malloc(len * 2);
     422                 :   WriteUnicodeLE(passbuf, password.get(), len);
     423                 : #else
     424               0 :   passbuf = (PRUint8 *) password.get();
     425                 : #endif
     426                 : 
     427               0 :   md4sum(passbuf, len * 2, hash);
     428                 : 
     429                 : #ifdef IS_BIG_ENDIAN
     430                 :   ZapBuf(passbuf, len * 2);
     431                 :   free(passbuf);
     432                 : #endif
     433               0 : }
     434                 : 
     435                 : //-----------------------------------------------------------------------------
     436                 : 
     437                 : /** 
     438                 :  * LM_Response generates the LM response given a 16-byte password hash and the
     439                 :  * challenge from the Type-2 message.
     440                 :  *
     441                 :  * @param hash
     442                 :  *        16-byte password hash
     443                 :  * @param challenge
     444                 :  *        8-byte challenge from Type-2 message
     445                 :  * @param response
     446                 :  *        24-byte buffer to contain the LM response upon return
     447                 :  */
     448                 : static void
     449               0 : LM_Response(const PRUint8 *hash, const PRUint8 *challenge, PRUint8 *response)
     450                 : {
     451                 :   PRUint8 keybytes[21], k1[8], k2[8], k3[8];
     452                 : 
     453               0 :   memcpy(keybytes, hash, 16);
     454               0 :   ZapBuf(keybytes + 16, 5);
     455                 : 
     456               0 :   des_makekey(keybytes     , k1);
     457               0 :   des_makekey(keybytes +  7, k2);
     458               0 :   des_makekey(keybytes + 14, k3);
     459                 : 
     460               0 :   des_encrypt(k1, challenge, response);
     461               0 :   des_encrypt(k2, challenge, response + 8);
     462               0 :   des_encrypt(k3, challenge, response + 16);
     463               0 : }
     464                 : 
     465                 : //-----------------------------------------------------------------------------
     466                 : 
     467                 : static nsresult
     468               0 : GenerateType1Msg(void **outBuf, PRUint32 *outLen)
     469                 : {
     470                 :   //
     471                 :   // verify that bufLen is sufficient
     472                 :   //
     473               0 :   *outLen = NTLM_TYPE1_HEADER_LEN;
     474               0 :   *outBuf = nsMemory::Alloc(*outLen);
     475               0 :   if (!*outBuf)
     476               0 :     return NS_ERROR_OUT_OF_MEMORY;
     477                 : 
     478                 :   //
     479                 :   // write out type 1 msg
     480                 :   //
     481               0 :   void *cursor = *outBuf;
     482                 : 
     483                 :   // 0 : signature
     484               0 :   cursor = WriteBytes(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE));
     485                 : 
     486                 :   // 8 : marker
     487               0 :   cursor = WriteBytes(cursor, NTLM_TYPE1_MARKER, sizeof(NTLM_TYPE1_MARKER));
     488                 : 
     489                 :   // 12 : flags
     490               0 :   cursor = WriteDWORD(cursor, NTLM_TYPE1_FLAGS);
     491                 : 
     492                 :   //
     493                 :   // NOTE: it is common for the domain and workstation fields to be empty.
     494                 :   //       this is true of Win2k clients, and my guess is that there is
     495                 :   //       little utility to sending these strings before the charset has
     496                 :   //       been negotiated.  we follow suite -- anyways, it doesn't hurt
     497                 :   //       to save some bytes on the wire ;-)
     498                 :   //
     499                 : 
     500                 :   // 16 : supplied domain security buffer (empty)
     501               0 :   cursor = WriteSecBuf(cursor, 0, 0);
     502                 : 
     503                 :   // 24 : supplied workstation security buffer (empty)
     504               0 :   cursor = WriteSecBuf(cursor, 0, 0);
     505                 : 
     506               0 :   return NS_OK;
     507                 : }
     508                 : 
     509                 : struct Type2Msg
     510                 : {
     511                 :   PRUint32    flags;         // NTLM_Xxx bitwise combination
     512                 :   PRUint8     challenge[8];  // 8 byte challenge
     513                 :   const void *target;        // target string (type depends on flags)
     514                 :   PRUint32    targetLen;     // target length in bytes
     515                 : };
     516                 : 
     517                 : static nsresult
     518               0 : ParseType2Msg(const void *inBuf, PRUint32 inLen, Type2Msg *msg)
     519                 : {
     520                 :   // make sure inBuf is long enough to contain a meaningful type2 msg.
     521                 :   //
     522                 :   // 0  NTLMSSP Signature
     523                 :   // 8  NTLM Message Type
     524                 :   // 12 Target Name
     525                 :   // 20 Flags
     526                 :   // 24 Challenge
     527                 :   // 32 end of header, start of optional data blocks
     528                 :   //
     529               0 :   if (inLen < NTLM_TYPE2_HEADER_LEN)
     530               0 :     return NS_ERROR_UNEXPECTED;
     531                 : 
     532               0 :   const PRUint8 *cursor = (const PRUint8 *) inBuf;
     533                 : 
     534                 :   // verify NTLMSSP signature
     535               0 :   if (memcmp(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)) != 0)
     536               0 :     return NS_ERROR_UNEXPECTED;
     537                 : 
     538               0 :   cursor += sizeof(NTLM_SIGNATURE);
     539                 : 
     540                 :   // verify Type-2 marker
     541               0 :   if (memcmp(cursor, NTLM_TYPE2_MARKER, sizeof(NTLM_TYPE2_MARKER)) != 0)
     542               0 :     return NS_ERROR_UNEXPECTED;
     543                 : 
     544               0 :   cursor += sizeof(NTLM_TYPE2_MARKER);
     545                 : 
     546                 :   // Read target name security buffer: ...
     547                 :   // ... read target length.
     548               0 :   PRUint32 targetLen = ReadUint16(cursor);
     549                 :   // ... skip next 16-bit "allocated space" value.
     550               0 :   ReadUint16(cursor);
     551                 :   // ... read offset from inBuf.
     552               0 :   PRUint32 offset = ReadUint32(cursor);
     553                 :   // Check the offset / length combo is in range of the input buffer, including
     554                 :   // integer overflow checking.
     555               0 :   if (NS_LIKELY(offset < offset + targetLen && offset + targetLen <= inLen)) {
     556               0 :     msg->targetLen = targetLen;
     557               0 :     msg->target = ((const PRUint8 *) inBuf) + offset;
     558                 :   }
     559                 :   else
     560                 :   {
     561                 :     // Do not error out, for (conservative) backward compatibility.
     562               0 :     msg->targetLen = 0;
     563               0 :     msg->target = NULL;
     564                 :   }
     565                 : 
     566                 :   // read flags
     567               0 :   msg->flags = ReadUint32(cursor);
     568                 : 
     569                 :   // read challenge
     570               0 :   memcpy(msg->challenge, cursor, sizeof(msg->challenge));
     571               0 :   cursor += sizeof(msg->challenge);
     572                 : 
     573                 : 
     574               0 :   LOG(("NTLM type 2 message:\n"));
     575               0 :   LogBuf("target", (const PRUint8 *) msg->target, msg->targetLen);
     576               0 :   LogBuf("flags", (const PRUint8 *) &msg->flags, 4);
     577               0 :   LogFlags(msg->flags);
     578               0 :   LogBuf("challenge", msg->challenge, sizeof(msg->challenge));
     579                 : 
     580                 :   // we currently do not implement LMv2/NTLMv2 or NTLM2 responses,
     581                 :   // so we can ignore target information.  we may want to enable
     582                 :   // support for these alternate mechanisms in the future.
     583               0 :   return NS_OK;
     584                 : }
     585                 : 
     586                 : static nsresult
     587               0 : GenerateType3Msg(const nsString &domain,
     588                 :                  const nsString &username,
     589                 :                  const nsString &password,
     590                 :                  const void     *inBuf,
     591                 :                  PRUint32        inLen,
     592                 :                  void          **outBuf,
     593                 :                  PRUint32       *outLen)
     594                 : {
     595                 :   // inBuf contains Type-2 msg (the challenge) from server
     596                 : 
     597                 :   nsresult rv;
     598                 :   Type2Msg msg;
     599                 : 
     600               0 :   rv = ParseType2Msg(inBuf, inLen, &msg);
     601               0 :   if (NS_FAILED(rv))
     602               0 :     return rv;
     603                 : 
     604               0 :   bool unicode = (msg.flags & NTLM_NegotiateUnicode);
     605                 : 
     606                 :   // temporary buffers for unicode strings
     607                 : #ifdef IS_BIG_ENDIAN
     608                 :   nsAutoString ucsDomainBuf, ucsUserBuf;
     609                 : #endif
     610               0 :   nsAutoString ucsHostBuf; 
     611                 :   // temporary buffers for oem strings
     612               0 :   nsCAutoString oemDomainBuf, oemUserBuf, oemHostBuf;
     613                 :   // pointers and lengths for the string buffers; encoding is unicode if
     614                 :   // the "negotiate unicode" flag was set in the Type-2 message.
     615                 :   const void *domainPtr, *userPtr, *hostPtr;
     616                 :   PRUint32 domainLen, userLen, hostLen;
     617                 : 
     618                 :   //
     619                 :   // get domain name
     620                 :   //
     621               0 :   if (unicode)
     622                 :   {
     623                 : #ifdef IS_BIG_ENDIAN
     624                 :     ucsDomainBuf = domain;
     625                 :     domainPtr = ucsDomainBuf.get();
     626                 :     domainLen = ucsDomainBuf.Length() * 2;
     627                 :     WriteUnicodeLE((void *) domainPtr, (const PRUnichar *) domainPtr,
     628                 :                    ucsDomainBuf.Length());
     629                 : #else
     630               0 :     domainPtr = domain.get();
     631               0 :     domainLen = domain.Length() * 2;
     632                 : #endif
     633                 :   }
     634                 :   else
     635                 :   {
     636               0 :     NS_CopyUnicodeToNative(domain, oemDomainBuf);
     637               0 :     domainPtr = oemDomainBuf.get();
     638               0 :     domainLen = oemDomainBuf.Length();
     639                 :   }
     640                 : 
     641                 :   //
     642                 :   // get user name
     643                 :   //
     644               0 :   if (unicode)
     645                 :   {
     646                 : #ifdef IS_BIG_ENDIAN
     647                 :     ucsUserBuf = username;
     648                 :     userPtr = ucsUserBuf.get();
     649                 :     userLen = ucsUserBuf.Length() * 2;
     650                 :     WriteUnicodeLE((void *) userPtr, (const PRUnichar *) userPtr,
     651                 :                    ucsUserBuf.Length());
     652                 : #else
     653               0 :     userPtr = username.get();
     654               0 :     userLen = username.Length() * 2;
     655                 : #endif
     656                 :   }
     657                 :   else
     658                 :   {
     659               0 :     NS_CopyUnicodeToNative(username, oemUserBuf);
     660               0 :     userPtr = oemUserBuf.get();
     661               0 :     userLen = oemUserBuf.Length();
     662                 :   }
     663                 : 
     664                 :   //
     665                 :   // get workstation name (use local machine's hostname)
     666                 :   //
     667                 :   char hostBuf[SYS_INFO_BUFFER_LENGTH];
     668               0 :   if (PR_GetSystemInfo(PR_SI_HOSTNAME, hostBuf, sizeof(hostBuf)) == PR_FAILURE)
     669               0 :     return NS_ERROR_UNEXPECTED;
     670               0 :   hostLen = strlen(hostBuf);
     671               0 :   if (unicode)
     672                 :   {
     673                 :     // hostname is ASCII, so we can do a simple zero-pad expansion:
     674               0 :     CopyASCIItoUTF16(nsDependentCString(hostBuf, hostLen), ucsHostBuf);
     675               0 :     hostPtr = ucsHostBuf.get();
     676               0 :     hostLen = ucsHostBuf.Length() * 2;
     677                 : #ifdef IS_BIG_ENDIAN
     678                 :     WriteUnicodeLE((void *) hostPtr, (const PRUnichar *) hostPtr,
     679                 :                    ucsHostBuf.Length());
     680                 : #endif
     681                 :   }
     682                 :   else
     683               0 :     hostPtr = hostBuf;
     684                 : 
     685                 :   //
     686                 :   // now that we have generated all of the strings, we can allocate outBuf.
     687                 :   //
     688                 :   *outLen = NTLM_TYPE3_HEADER_LEN + hostLen + domainLen + userLen +
     689               0 :             LM_RESP_LEN + NTLM_RESP_LEN;
     690               0 :   *outBuf = nsMemory::Alloc(*outLen);
     691               0 :   if (!*outBuf)
     692               0 :     return NS_ERROR_OUT_OF_MEMORY;
     693                 : 
     694                 :   //
     695                 :   // next, we compute the LM and NTLM responses.
     696                 :   //
     697                 :   PRUint8 lmResp[LM_RESP_LEN], ntlmResp[NTLM_RESP_LEN], ntlmHash[NTLM_HASH_LEN];
     698               0 :   if (msg.flags & NTLM_NegotiateNTLM2Key)
     699                 :   {
     700                 :     // compute NTLM2 session response
     701                 :     PRUint8 sessionHash[16], temp[16];
     702                 : 
     703               0 :     PK11_GenerateRandom(lmResp, 8);
     704               0 :     memset(lmResp + 8, 0, LM_RESP_LEN - 8);
     705                 : 
     706               0 :     memcpy(temp, msg.challenge, 8);
     707               0 :     memcpy(temp + 8, lmResp, 8);
     708               0 :     md5sum(temp, 16, sessionHash);
     709                 : 
     710               0 :     NTLM_Hash(password, ntlmHash);
     711               0 :     LM_Response(ntlmHash, sessionHash, ntlmResp);
     712                 :   }
     713                 :   else
     714                 :   {
     715               0 :     NTLM_Hash(password, ntlmHash);
     716               0 :     LM_Response(ntlmHash, msg.challenge, ntlmResp);
     717                 : 
     718               0 :     if (SendLM())
     719                 :     {
     720                 :       PRUint8 lmHash[LM_HASH_LEN];
     721               0 :       LM_Hash(password, lmHash);
     722               0 :       LM_Response(lmHash, msg.challenge, lmResp);
     723                 :     }
     724                 :     else
     725                 :     {
     726                 :       // According to http://davenport.sourceforge.net/ntlm.html#ntlmVersion2,
     727                 :       // the correct way to not send the LM hash is to send the NTLM hash twice
     728                 :       // in both the LM and NTLM response fields.
     729               0 :       LM_Response(ntlmHash, msg.challenge, lmResp);
     730                 :     }
     731                 :   }
     732                 : 
     733                 :   //
     734                 :   // finally, we assemble the Type-3 msg :-)
     735                 :   //
     736               0 :   void *cursor = *outBuf;
     737                 :   PRUint32 offset;
     738                 : 
     739                 :   // 0 : signature
     740               0 :   cursor = WriteBytes(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE));
     741                 : 
     742                 :   // 8 : marker
     743               0 :   cursor = WriteBytes(cursor, NTLM_TYPE3_MARKER, sizeof(NTLM_TYPE3_MARKER));
     744                 : 
     745                 :   // 12 : LM response sec buf
     746               0 :   offset = NTLM_TYPE3_HEADER_LEN + domainLen + userLen + hostLen;
     747               0 :   cursor = WriteSecBuf(cursor, LM_RESP_LEN, offset);
     748               0 :   memcpy((PRUint8 *) *outBuf + offset, lmResp, LM_RESP_LEN);
     749                 : 
     750                 :   // 20 : NTLM response sec buf
     751               0 :   offset += LM_RESP_LEN;
     752               0 :   cursor = WriteSecBuf(cursor, NTLM_RESP_LEN, offset);
     753               0 :   memcpy((PRUint8 *) *outBuf + offset, ntlmResp, NTLM_RESP_LEN);
     754                 : 
     755                 :   // 28 : domain name sec buf
     756               0 :   offset = NTLM_TYPE3_HEADER_LEN;
     757               0 :   cursor = WriteSecBuf(cursor, domainLen, offset);
     758               0 :   memcpy((PRUint8 *) *outBuf + offset, domainPtr, domainLen);
     759                 : 
     760                 :   // 36 : user name sec buf
     761               0 :   offset += domainLen;
     762               0 :   cursor = WriteSecBuf(cursor, userLen, offset);
     763               0 :   memcpy((PRUint8 *) *outBuf + offset, userPtr, userLen);
     764                 : 
     765                 :   // 44 : workstation (host) name sec buf
     766               0 :   offset += userLen;
     767               0 :   cursor = WriteSecBuf(cursor, hostLen, offset);
     768               0 :   memcpy((PRUint8 *) *outBuf + offset, hostPtr, hostLen);
     769                 : 
     770                 :   // 52 : session key sec buf (not used)
     771               0 :   cursor = WriteSecBuf(cursor, 0, 0);
     772                 : 
     773                 :   // 60 : negotiated flags
     774               0 :   cursor = WriteDWORD(cursor, msg.flags & NTLM_TYPE1_FLAGS);
     775                 : 
     776               0 :   return NS_OK;
     777                 : }
     778                 : 
     779                 : //-----------------------------------------------------------------------------
     780                 : 
     781               5 : NS_IMPL_ISUPPORTS1(nsNTLMAuthModule, nsIAuthModule)
     782                 : 
     783               3 : nsNTLMAuthModule::~nsNTLMAuthModule()
     784                 : {
     785               1 :   ZapString(mPassword);
     786               4 : }
     787                 : 
     788                 : nsresult
     789               1 : nsNTLMAuthModule::InitTest()
     790                 : {
     791               2 :   nsNSSShutDownPreventionLock locker;
     792                 :   //
     793                 :   // disable NTLM authentication when FIPS mode is enabled.
     794                 :   //
     795               1 :   return PK11_IsFIPS() ? NS_ERROR_NOT_AVAILABLE : NS_OK;
     796                 : }
     797                 : 
     798                 : NS_IMETHODIMP
     799               0 : nsNTLMAuthModule::Init(const char      *serviceName,
     800                 :                        PRUint32         serviceFlags,
     801                 :                        const PRUnichar *domain,
     802                 :                        const PRUnichar *username,
     803                 :                        const PRUnichar *password)
     804                 : {
     805               0 :   NS_ASSERTION(serviceFlags == nsIAuthModule::REQ_DEFAULT, "unexpected service flags");
     806                 : 
     807               0 :   mDomain = domain;
     808               0 :   mUsername = username;
     809               0 :   mPassword = password;
     810               0 :   return NS_OK;
     811                 : }
     812                 : 
     813                 : NS_IMETHODIMP
     814               0 : nsNTLMAuthModule::GetNextToken(const void *inToken,
     815                 :                                PRUint32    inTokenLen,
     816                 :                                void      **outToken,
     817                 :                                PRUint32   *outTokenLen)
     818                 : {
     819                 :   nsresult rv;
     820               0 :   nsNSSShutDownPreventionLock locker;
     821                 :   //
     822                 :   // disable NTLM authentication when FIPS mode is enabled.
     823                 :   //
     824               0 :   if (PK11_IsFIPS())
     825               0 :     return NS_ERROR_NOT_AVAILABLE;
     826                 : 
     827                 :   // if inToken is non-null, then assume it contains a type 2 message...
     828               0 :   if (inToken)
     829                 :   {
     830               0 :     LogToken("in-token", inToken, inTokenLen);
     831                 :     rv = GenerateType3Msg(mDomain, mUsername, mPassword, inToken,
     832               0 :                           inTokenLen, outToken, outTokenLen);
     833                 :   }
     834                 :   else
     835                 :   {
     836               0 :     rv = GenerateType1Msg(outToken, outTokenLen);
     837                 :   }
     838                 : 
     839                 : #ifdef PR_LOGGING
     840               0 :   if (NS_SUCCEEDED(rv))
     841               0 :     LogToken("out-token", *outToken, *outTokenLen);
     842                 : #endif
     843                 : 
     844               0 :   return rv;
     845                 : }
     846                 : 
     847                 : NS_IMETHODIMP
     848               0 : nsNTLMAuthModule::Unwrap(const void *inToken,
     849                 :                         PRUint32    inTokenLen,
     850                 :                         void      **outToken,
     851                 :                         PRUint32   *outTokenLen)
     852                 : {
     853               0 :   return NS_ERROR_NOT_IMPLEMENTED;
     854                 : }
     855                 : 
     856                 : NS_IMETHODIMP
     857               0 : nsNTLMAuthModule::Wrap(const void *inToken,
     858                 :                        PRUint32    inTokenLen,
     859                 :                        bool        confidential,
     860                 :                        void      **outToken,
     861                 :                        PRUint32   *outTokenLen)
     862                 : {
     863               0 :   return NS_ERROR_NOT_IMPLEMENTED;
     864                 : }
     865                 : 
     866                 : //-----------------------------------------------------------------------------
     867                 : // DES support code
     868                 : 
     869                 : // set odd parity bit (in least significant bit position)
     870                 : static PRUint8
     871               0 : des_setkeyparity(PRUint8 x)
     872                 : {
     873               0 :   if ((((x >> 7) ^ (x >> 6) ^ (x >> 5) ^
     874                 :         (x >> 4) ^ (x >> 3) ^ (x >> 2) ^
     875                 :         (x >> 1)) & 0x01) == 0)
     876               0 :     x |= 0x01;
     877                 :   else
     878               0 :     x &= 0xfe;
     879               0 :   return x;
     880                 : }
     881                 : 
     882                 : // build 64-bit des key from 56-bit raw key
     883                 : static void
     884               0 : des_makekey(const PRUint8 *raw, PRUint8 *key)
     885                 : {
     886               0 :   key[0] = des_setkeyparity(raw[0]);
     887               0 :   key[1] = des_setkeyparity((raw[0] << 7) | (raw[1] >> 1));
     888               0 :   key[2] = des_setkeyparity((raw[1] << 6) | (raw[2] >> 2));
     889               0 :   key[3] = des_setkeyparity((raw[2] << 5) | (raw[3] >> 3));
     890               0 :   key[4] = des_setkeyparity((raw[3] << 4) | (raw[4] >> 4));
     891               0 :   key[5] = des_setkeyparity((raw[4] << 3) | (raw[5] >> 5));
     892               0 :   key[6] = des_setkeyparity((raw[5] << 2) | (raw[6] >> 6));
     893               0 :   key[7] = des_setkeyparity((raw[6] << 1));
     894               0 : }
     895                 : 
     896                 : // run des encryption algorithm (using NSS)
     897                 : static void
     898               0 : des_encrypt(const PRUint8 *key, const PRUint8 *src, PRUint8 *hash)
     899                 : {
     900               0 :   CK_MECHANISM_TYPE cipherMech = CKM_DES_ECB;
     901               0 :   PK11SlotInfo *slot = nsnull;
     902               0 :   PK11SymKey *symkey = nsnull;
     903               0 :   PK11Context *ctxt = nsnull;
     904               0 :   SECItem keyItem, *param = nsnull;
     905                 :   SECStatus rv;
     906                 :   unsigned int n;
     907                 :   
     908               0 :   slot = PK11_GetBestSlot(cipherMech, nsnull);
     909               0 :   if (!slot)
     910                 :   {
     911               0 :     NS_ERROR("no slot");
     912               0 :     goto done;
     913                 :   }
     914                 : 
     915               0 :   keyItem.data = (PRUint8 *) key;
     916               0 :   keyItem.len = 8;
     917                 :   symkey = PK11_ImportSymKey(slot, cipherMech,
     918                 :                              PK11_OriginUnwrap, CKA_ENCRYPT,
     919               0 :                              &keyItem, nsnull);
     920               0 :   if (!symkey)
     921                 :   {
     922               0 :     NS_ERROR("no symkey");
     923               0 :     goto done;
     924                 :   }
     925                 : 
     926                 :   // no initialization vector required
     927               0 :   param = PK11_ParamFromIV(cipherMech, nsnull);
     928               0 :   if (!param)
     929                 :   {
     930               0 :     NS_ERROR("no param");
     931               0 :     goto done;
     932                 :   }
     933                 : 
     934                 :   ctxt = PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT,
     935               0 :                                     symkey, param);
     936               0 :   if (!ctxt)
     937                 :   {
     938               0 :     NS_ERROR("no context");
     939               0 :     goto done;
     940                 :   }
     941                 : 
     942               0 :   rv = PK11_CipherOp(ctxt, hash, (int *) &n, 8, (PRUint8 *) src, 8);
     943               0 :   if (rv != SECSuccess)
     944                 :   {
     945               0 :     NS_ERROR("des failure");
     946               0 :     goto done;
     947                 :   }
     948                 : 
     949               0 :   rv = PK11_DigestFinal(ctxt, hash+8, &n, 0);
     950               0 :   if (rv != SECSuccess)
     951                 :   {
     952               0 :     NS_ERROR("des failure");
     953               0 :     goto done;
     954                 :   }
     955                 : 
     956                 : done:
     957               0 :   if (ctxt)
     958               0 :     PK11_DestroyContext(ctxt, true);
     959               0 :   if (symkey)
     960               0 :     PK11_FreeSymKey(symkey);
     961               0 :   if (param)
     962               0 :     SECITEM_FreeItem(param, true);
     963               0 :   if (slot)
     964               0 :     PK11_FreeSlot(slot);
     965               0 : }
     966                 : 
     967                 : //-----------------------------------------------------------------------------
     968                 : // MD5 support code
     969                 : 
     970               0 : static void md5sum(const PRUint8 *input, PRUint32 inputLen, PRUint8 *result)
     971                 : {
     972               0 :   PK11Context *ctxt = PK11_CreateDigestContext(SEC_OID_MD5);
     973               0 :   if (ctxt)
     974                 :   {
     975               0 :     if (PK11_DigestBegin(ctxt) == SECSuccess)
     976                 :     {
     977               0 :       if (PK11_DigestOp(ctxt, input, inputLen) == SECSuccess)
     978                 :       {
     979               0 :         PRUint32 resultLen = 16;
     980               0 :         PK11_DigestFinal(ctxt, result, &resultLen, resultLen);
     981                 :       }
     982                 :     }
     983               0 :     PK11_DestroyContext(ctxt, true);
     984                 :   }
     985            4392 : }

Generated by: LCOV version 1.7