nsNTLMAuthModule.cpp 33 KB

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